peachsim 0.1.638 → 0.1.640
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/command-registry.ts +1 -0
- package/cli/commands/control.ts +75 -6
- package/cli/commands/swift.ts +326 -0
- package/cli/main.ts +11 -0
- package/cli/outbound-endpoints.ts +5 -1
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +13 -4
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +389 -232
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +89 -8
- package/dist-lib/swift-submit.mjs +78 -8
- package/dist-lib/swift.cjs +16 -33308
- package/dist-lib/vite-swift.cjs +422 -247
- package/dist-lib/vite.cjs +13 -4
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +1 -0
- package/src/assetCatalogContract.ts +16 -0
- package/src/dot-env.ts +148 -0
- package/src/metro-runtime-source.ts +15 -0
- package/src/swift-guest.ts +51 -0
- package/src/swift-host.ts +900 -0
- package/src/swift-submit.ts +97 -6
- package/src/swift.ts +36 -8
- package/src/swiftContract.ts +52 -0
- package/src/vite-plugin-one.ts +4 -3
- package/src/vite-plugin-swift.ts +43 -755
package/src/swift-submit.ts
CHANGED
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
export const SWIFT_COMPILE_PATH = '/api/swift-compile'
|
|
24
|
+
export const SWIFT_PACKAGE_PATH = '/__peach/swift-package/'
|
|
25
|
+
export const SWIFT_HMR_PATH = '/__peach/swift-hmr'
|
|
26
|
+
|
|
27
|
+
// shared with the compile service; collection enforces these before reading.
|
|
28
|
+
export const MAX_SWIFT_COMPILE_FILES = 256
|
|
29
|
+
export const MAX_SWIFT_COMPILE_SOURCE_BYTES = 2 * 1024 * 1024
|
|
30
|
+
export const MAX_SWIFT_COMPILE_RESOURCES = 128
|
|
31
|
+
export const MAX_SWIFT_COMPILE_RESOURCE_BYTES = 2 * 1024 * 1024
|
|
32
|
+
export const MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024
|
|
33
|
+
export const MAX_SWIFT_COMPILE_IMAGES = 128
|
|
34
|
+
export const MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024
|
|
35
|
+
export const MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024
|
|
24
36
|
|
|
25
37
|
/**
|
|
26
38
|
* what an artifact needs from the mount that instantiates it. every request
|
|
@@ -31,8 +43,9 @@ export const SWIFT_COMPILE_PATH = '/api/swift-compile'
|
|
|
31
43
|
* its host. 1: the host fills Sources/PeachICU's reserved icu data and provides
|
|
32
44
|
* `peach.icu_data_v1` (`packages/sootsim-swift/src/icuData.ts`). a request
|
|
33
45
|
* without one comes from before this field, a host that is 0.
|
|
46
|
+
* 2: scroll anchors carry numeric unit coordinates to the kit.
|
|
34
47
|
*/
|
|
35
|
-
export const SWIFT_HOST_ABI =
|
|
48
|
+
export const SWIFT_HOST_ABI = 2
|
|
36
49
|
|
|
37
50
|
export interface SwiftImageUpload {
|
|
38
51
|
/** the raster file picked for the asset (has the extension). */
|
|
@@ -142,6 +155,7 @@ export interface SwiftCompileContext {
|
|
|
142
155
|
* app must pass one.
|
|
143
156
|
*/
|
|
144
157
|
endpoint?: string
|
|
158
|
+
signal?: AbortSignal
|
|
145
159
|
}
|
|
146
160
|
|
|
147
161
|
export type SwiftCompileSubmit = (work: {
|
|
@@ -170,6 +184,7 @@ export function httpSwiftCompileSubmit(
|
|
|
170
184
|
try {
|
|
171
185
|
response = await fetch(url, {
|
|
172
186
|
method: 'POST',
|
|
187
|
+
signal: context.signal,
|
|
173
188
|
headers: {
|
|
174
189
|
'content-type': 'application/json',
|
|
175
190
|
...(authorization ? { authorization } : {}),
|
|
@@ -192,8 +207,68 @@ export function httpSwiftCompileSubmit(
|
|
|
192
207
|
`contrast-bundler: the swift compile for ${work.entry} answered ${response.status}${detail ? `: ${detail}` : ''}`,
|
|
193
208
|
)
|
|
194
209
|
}
|
|
195
|
-
|
|
210
|
+
const outcome: unknown = await response.json()
|
|
211
|
+
if (!isSwiftCompileOutcome(outcome)) {
|
|
212
|
+
throw new Error('swift compile: the service returned invalid artifact metadata')
|
|
213
|
+
}
|
|
214
|
+
return outcome
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
219
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function isSwiftNativeModules(value: unknown): value is SwiftNativeModules {
|
|
223
|
+
return (
|
|
224
|
+
isRecord(value) &&
|
|
225
|
+
typeof value.packageId === 'string' &&
|
|
226
|
+
typeof value.hash === 'string' &&
|
|
227
|
+
isRecord(value.files) &&
|
|
228
|
+
isRecord(value.modules) &&
|
|
229
|
+
[...Object.values(value.files), ...Object.values(value.modules)].every(
|
|
230
|
+
(names) => Array.isArray(names) && names.every((name) => typeof name === 'string'),
|
|
231
|
+
) &&
|
|
232
|
+
Array.isArray(value.defaultViewFiles) &&
|
|
233
|
+
value.defaultViewFiles.every((file) => typeof file === 'string')
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function isSwiftCompileOutcome(value: unknown): value is SwiftCompileOutcome {
|
|
238
|
+
if (!isRecord(value)) return false
|
|
239
|
+
switch (value.status) {
|
|
240
|
+
case 'published':
|
|
241
|
+
return (
|
|
242
|
+
typeof value.artifactUrl === 'string' &&
|
|
243
|
+
typeof value.icuUrl === 'string' &&
|
|
244
|
+
typeof value.hash === 'string' &&
|
|
245
|
+
/^[a-f0-9]{64}$/.test(value.hash) &&
|
|
246
|
+
(value.imageUrls === undefined ||
|
|
247
|
+
(isRecord(value.imageUrls) &&
|
|
248
|
+
Object.values(value.imageUrls).every((url) => typeof url === 'string'))) &&
|
|
249
|
+
(value.native === undefined || isSwiftNativeModules(value.native))
|
|
250
|
+
)
|
|
251
|
+
case 'compiling':
|
|
252
|
+
return typeof value.hash === 'string' && /^[a-f0-9]{64}$/.test(value.hash)
|
|
253
|
+
case 'refused':
|
|
254
|
+
case 'failed':
|
|
255
|
+
return typeof value.detail === 'string'
|
|
256
|
+
default:
|
|
257
|
+
return false
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function compileAssetUrl(value: string, origin: string): string {
|
|
262
|
+
const url = new URL(value, origin)
|
|
263
|
+
if (
|
|
264
|
+
(url.protocol !== 'http:' && url.protocol !== 'https:') ||
|
|
265
|
+
url.username ||
|
|
266
|
+
url.password ||
|
|
267
|
+
url.origin !== new URL(origin).origin
|
|
268
|
+
) {
|
|
269
|
+
throw new Error('swift compile: artifact address escapes the compile origin')
|
|
196
270
|
}
|
|
271
|
+
return url.href
|
|
197
272
|
}
|
|
198
273
|
|
|
199
274
|
export interface SwiftModuleAddress {
|
|
@@ -215,7 +290,7 @@ function resolveImageUrls(
|
|
|
215
290
|
): Record<string, string> {
|
|
216
291
|
const resolved: Record<string, string> = {}
|
|
217
292
|
for (const [name, url] of Object.entries(urls)) {
|
|
218
|
-
resolved[name] =
|
|
293
|
+
resolved[name] = compileAssetUrl(url, origin)
|
|
219
294
|
}
|
|
220
295
|
return resolved
|
|
221
296
|
}
|
|
@@ -239,22 +314,38 @@ export async function compileSwiftProject(
|
|
|
239
314
|
packageId?: string
|
|
240
315
|
},
|
|
241
316
|
origin: string,
|
|
317
|
+
signal?: AbortSignal,
|
|
242
318
|
): Promise<SwiftModuleAddress> {
|
|
243
319
|
while (true) {
|
|
320
|
+
signal?.throwIfAborted()
|
|
244
321
|
const outcome = await submit(work)
|
|
245
322
|
switch (outcome.status) {
|
|
246
323
|
case 'published':
|
|
247
324
|
return {
|
|
248
|
-
url:
|
|
325
|
+
url: compileAssetUrl(outcome.artifactUrl, origin),
|
|
249
326
|
hash: outcome.hash,
|
|
250
|
-
icuUrl:
|
|
327
|
+
icuUrl: compileAssetUrl(outcome.icuUrl, origin),
|
|
251
328
|
...(outcome.imageUrls === undefined
|
|
252
329
|
? {}
|
|
253
330
|
: { imageUrls: resolveImageUrls(outcome.imageUrls, origin) }),
|
|
254
331
|
...(outcome.native === undefined ? {} : { native: outcome.native }),
|
|
255
332
|
}
|
|
256
333
|
case 'compiling':
|
|
257
|
-
await new Promise((resolve) =>
|
|
334
|
+
await new Promise<void>((resolve, reject) => {
|
|
335
|
+
const finish = () => {
|
|
336
|
+
signal?.removeEventListener('abort', abort)
|
|
337
|
+
resolve()
|
|
338
|
+
}
|
|
339
|
+
const timer = setTimeout(finish, POLL_INTERVAL_MS)
|
|
340
|
+
const abort = () => {
|
|
341
|
+
clearTimeout(timer)
|
|
342
|
+
signal?.removeEventListener('abort', abort)
|
|
343
|
+
const reason = signal?.reason
|
|
344
|
+
reject(reason instanceof Error ? reason : new Error(String(reason)))
|
|
345
|
+
}
|
|
346
|
+
signal?.addEventListener('abort', abort, { once: true })
|
|
347
|
+
if (signal?.aborted) abort()
|
|
348
|
+
})
|
|
258
349
|
continue
|
|
259
350
|
case 'refused':
|
|
260
351
|
case 'failed':
|
package/src/swift.ts
CHANGED
|
@@ -1,9 +1,37 @@
|
|
|
1
|
-
// the
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
createSwiftEntry,
|
|
5
|
-
callSwiftModule,
|
|
6
|
-
useSwiftHost,
|
|
1
|
+
// the public entry calls the existing guest host; the engine owns the mount.
|
|
2
|
+
import {
|
|
3
|
+
isSwiftRuntimeHost,
|
|
7
4
|
type SwiftEntryOptions,
|
|
8
|
-
type
|
|
9
|
-
} from '
|
|
5
|
+
type SwiftRuntimeHost,
|
|
6
|
+
} from './swiftContract'
|
|
7
|
+
export type { SwiftEntryOptions, SwiftModuleOptions } from './swiftContract'
|
|
8
|
+
|
|
9
|
+
function swiftHost(): SwiftRuntimeHost {
|
|
10
|
+
const modules: unknown = Reflect.get(globalThis, '__contrastHostModules')
|
|
11
|
+
const host: unknown =
|
|
12
|
+
typeof modules === 'object' && modules !== null
|
|
13
|
+
? Reflect.get(modules, 'peachsim/swift')
|
|
14
|
+
: undefined
|
|
15
|
+
if (!isSwiftRuntimeHost(host)) {
|
|
16
|
+
throw new Error('peachsim/swift requires the Peach runtime host')
|
|
17
|
+
}
|
|
18
|
+
return host
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createSwiftEntry(options: SwiftEntryOptions) {
|
|
22
|
+
return swiftHost().createSwiftEntry(options)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useSwiftHost(options: SwiftEntryOptions, props: Record<string, unknown>) {
|
|
26
|
+
return swiftHost().useSwiftHost(options, props)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function callSwiftModule(
|
|
30
|
+
options: SwiftEntryOptions,
|
|
31
|
+
module: string,
|
|
32
|
+
method: string,
|
|
33
|
+
args: unknown[],
|
|
34
|
+
contractHash: string,
|
|
35
|
+
) {
|
|
36
|
+
return swiftHost().callSwiftModule(options, module, method, args, contractHash)
|
|
37
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AppCatalogColor,
|
|
3
|
+
SfSymbolVector,
|
|
4
|
+
SwiftImageSource,
|
|
5
|
+
} from './assetCatalogContract'
|
|
6
|
+
import type { ComponentType } from 'react'
|
|
7
|
+
|
|
8
|
+
export interface SwiftModuleOptions {
|
|
9
|
+
// the host serves the artifact, icu data and named image bytes.
|
|
10
|
+
url: string
|
|
11
|
+
// a changed hash hot reloads the shared package instance with its state.
|
|
12
|
+
hash: string
|
|
13
|
+
icuUrl?: string
|
|
14
|
+
exports?: readonly string[]
|
|
15
|
+
resources?: Record<string, SwiftImageSource>
|
|
16
|
+
// main-bundle files are base64 bytes exposed to wasm through its read-only /res.
|
|
17
|
+
bundleFiles?: Record<string, string>
|
|
18
|
+
colors?: Record<string, AppCatalogColor>
|
|
19
|
+
symbols?: Record<string, SfSymbolVector>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SwiftEntryOptions extends SwiftModuleOptions {
|
|
23
|
+
// only the standalone preview owns the app bundle; imports retain the host catalog.
|
|
24
|
+
mainBundle?: boolean
|
|
25
|
+
// the package/source path keeps a root's identity across module reloads.
|
|
26
|
+
rootId?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SwiftRuntimeHost {
|
|
30
|
+
createSwiftEntry(options: SwiftEntryOptions): ComponentType<Record<string, unknown>>
|
|
31
|
+
useSwiftHost(options: SwiftEntryOptions, props: Record<string, unknown>): ComponentType
|
|
32
|
+
callSwiftModule(
|
|
33
|
+
options: SwiftEntryOptions,
|
|
34
|
+
module: string,
|
|
35
|
+
method: string,
|
|
36
|
+
args: unknown[],
|
|
37
|
+
contractHash: string,
|
|
38
|
+
): Promise<unknown>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isSwiftRuntimeHost(host: unknown): host is SwiftRuntimeHost {
|
|
42
|
+
return !(
|
|
43
|
+
typeof host !== 'object' ||
|
|
44
|
+
host === null ||
|
|
45
|
+
!('createSwiftEntry' in host) ||
|
|
46
|
+
typeof host.createSwiftEntry !== 'function' ||
|
|
47
|
+
!('useSwiftHost' in host) ||
|
|
48
|
+
typeof host.useSwiftHost !== 'function' ||
|
|
49
|
+
!('callSwiftModule' in host) ||
|
|
50
|
+
typeof host.callSwiftModule !== 'function'
|
|
51
|
+
)
|
|
52
|
+
}
|
package/src/vite-plugin-one.ts
CHANGED
|
@@ -28,10 +28,10 @@ import {
|
|
|
28
28
|
serveRuntimeFile,
|
|
29
29
|
SOOTSIM_RUNTIME_MISSING_MESSAGE,
|
|
30
30
|
} from './runtime-assets'
|
|
31
|
+
import { SWIFT_HMR_PATH, SWIFT_PACKAGE_PATH } from './swift-submit'
|
|
31
32
|
import type { PeachPluginOptions } from './vite'
|
|
32
33
|
import type { Plugin } from 'vite'
|
|
33
34
|
|
|
34
|
-
const SWIFT_HMR_PATH = '/__peach/swift-hmr'
|
|
35
35
|
// every swift route sits under this prefix. the swift host (compiler client,
|
|
36
36
|
// resource packer, module glue) loads on the first request for one, so an app
|
|
37
37
|
// that imports no swift never evaluates it.
|
|
@@ -154,7 +154,8 @@ export function rnxPlugin(options: PeachPluginOptions = {}): Plugin {
|
|
|
154
154
|
})
|
|
155
155
|
.catch(next)
|
|
156
156
|
})
|
|
157
|
-
server.watcher.on('
|
|
157
|
+
server.watcher.on('all', (event, file) => {
|
|
158
|
+
if (event !== 'add' && event !== 'unlink' && event !== 'change') return
|
|
158
159
|
if (activeSwiftPackages.size === 0) return
|
|
159
160
|
const moduleRoot = moduleRootFor()
|
|
160
161
|
let packages: Map<string, string>
|
|
@@ -209,7 +210,7 @@ export function rnxPlugin(options: PeachPluginOptions = {}): Plugin {
|
|
|
209
210
|
loadSwiftHost()
|
|
210
211
|
.then((host) => {
|
|
211
212
|
if (host.serveSwiftPackageAsset(pathname, res)) return
|
|
212
|
-
const prefix =
|
|
213
|
+
const prefix = SWIFT_PACKAGE_PATH
|
|
213
214
|
if (!pathname.startsWith(prefix)) return next()
|
|
214
215
|
if (!swiftSockets) {
|
|
215
216
|
res.statusCode = 501
|