| 85 | } |
| 86 | |
| 87 | export class SpritesHandle implements SandboxHandle { |
| 88 | readonly id: string |
| 89 | readonly provider = 'sprites' |
| 90 | readonly workspaceRoot: string |
| 91 | readonly capabilities = SPRITES_CAPS |
| 92 | readonly fs: SandboxHandle['fs'] |
| 93 | readonly git: SandboxHandle['git'] |
| 94 | readonly process: SandboxHandle['process'] |
| 95 | readonly ports: SandboxHandle['ports'] |
| 96 | readonly env: SandboxHandle['env'] |
| 97 | |
| 98 | private readonly client: SpritesClientLike |
| 99 | private readonly name: string |
| 100 | private readonly url: string |
| 101 | private readonly workdir: string |
| 102 | private readonly httpPort: number |
| 103 | private readonly urlAuth: SpriteUrlAuth |
| 104 | private readonly envVars: Record<string, string> = {} |
| 105 | |
| 106 | constructor(deps: SpritesHandleDeps) { |
| 107 | this.client = deps.client |
| 108 | this.name = deps.name |
| 109 | this.url = deps.url |
| 110 | this.workdir = deps.workdir |
| 111 | this.workspaceRoot = deps.workdir |
| 112 | this.httpPort = deps.httpPort ?? SPRITE_DEFAULT_HTTP_PORT |
| 113 | this.urlAuth = deps.urlAuth ?? 'public' |
| 114 | this.id = deps.name |
| 115 | |
| 116 | this.process = { |
| 117 | exec: (command, opts) => this.exec(command, opts), |
| 118 | spawn: (command, opts) => this.spawnProcess(command, opts), |
| 119 | } |
| 120 | |
| 121 | this.fs = { |
| 122 | read: async (p) => |
| 123 | new TextDecoder().decode( |
| 124 | await this.client.fsRead(this.name, this.abs(p)), |
| 125 | ), |
| 126 | readBytes: (p) => this.client.fsRead(this.name, this.abs(p)), |
| 127 | write: (p, data) => |
| 128 | this.client.fsWrite( |
| 129 | this.name, |
| 130 | this.abs(p), |
| 131 | typeof data === 'string' ? new TextEncoder().encode(data) : data, |
| 132 | ), |
| 133 | list: async (p) => { |
| 134 | const entries = await this.client.fsList(this.name, this.abs(p)) |
| 135 | // Native paths are absolute Sprite paths; re-root them under the |
| 136 | // caller's virtual path so consumers stay provider-agnostic. |
| 137 | const base = p.replace(/\/$/, '') |
| 138 | return entries.map((entry) => ({ |
| 139 | name: entry.name, |
| 140 | path: `${base}/${entry.name}`, |
| 141 | type: entry.type, |
| 142 | })) |
| 143 | }, |
| 144 | mkdir: async (p) => { |
nothing calls this directly
no outgoing calls
no test coverage detected