@swifttui/build 0.13.5 → 0.15.0

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/README.md CHANGED
@@ -6,8 +6,8 @@ compile a SwiftTUI app to `wasm32-wasi` and capture its scene manifest.**
6
6
  [![npm](https://img.shields.io/npm/v/@swifttui/build)](https://www.npmjs.com/package/@swifttui/build)
7
7
  ![License](https://img.shields.io/badge/license-MIT-3DA639)
8
8
 
9
- `@swifttui/build` turns a SwiftTUI app into the two artifacts the browser needs:
10
- an `app.wasm` and a `scene-manifest.json`. It drives the Swift toolchain, runs a
9
+ `@swifttui/build` produces an `app.wasm`, a `scene-manifest.json`, and the DOM
10
+ host's bundled font assets and license notice. It drives the Swift toolchain, runs a
11
11
  browser `WebAssembly.compile` validation pass, and packages the result. It
12
12
  is separate from [`@swifttui/web`](https://www.npmjs.com/package/@swifttui/web),
13
13
  the browser runtime. Thus, runtime imports do not include Swift processes, Node
@@ -53,6 +53,14 @@ await buildSwiftTUIWebApp({
53
53
  });
54
54
  ```
55
55
 
56
+ The full build copies the runtime package's four verified WOFF2 faces, their
57
+ manifest and OFL notice into `assets/swifttui-fonts/2184c1f2bac4/`. Deploy that
58
+ directory with the app. Build systems that package WASM separately can use
59
+ `await copyDomFontAssets(outputDirectory)` from `@swifttui/build`; it validates
60
+ the installed asset hashes before copying. Runtime `domFont.assetBase` can
61
+ point at another same-origin asset directory. Font loading does not depend on
62
+ an external font service.
63
+
56
64
  Toolchain defaults match the repo:
57
65
 
58
66
  - Swift command: `swiftly run swift` when `swiftly` is on `PATH`, otherwise
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, hasRequiredWasmFlags, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines } from "./src/build/resolveSwiftArtifacts.js";
2
2
  import { BuildAppWasmOptions, buildAppWasm, packageBrowserValidatedWasm } from "./src/build/buildAppWasm.js";
3
3
  import { BuildSwiftTUIWebAppOptions, buildSwiftTUIWebApp } from "./src/build/buildSwiftTUIWebApp.js";
4
+ import { copyDomFontAssets } from "./src/build/copyDomFontAssets.js";
4
5
  import { GenerateSceneManifestOptions, generateSceneManifest } from "./src/build/generateSceneManifest.js";
5
- export { BuildAppWasmOptions, BuildSwiftTUIWebAppOptions, GenerateSceneManifestOptions, ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, buildAppWasm, buildSwiftTUIWebApp, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
6
+ export { BuildAppWasmOptions, BuildSwiftTUIWebAppOptions, GenerateSceneManifestOptions, ResolveSwiftArtifactsOptions, SwiftArtifactPaths, WasmBuildConfiguration, buildAppWasm, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, hasRequiredWasmFlags, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines } from "./src/build/resolveSwiftArtifacts.js";
2
2
  import { buildAppWasm, packageBrowserValidatedWasm } from "./src/build/buildAppWasm.js";
3
+ import { copyDomFontAssets } from "./src/build/copyDomFontAssets.js";
3
4
  import { generateSceneManifest } from "./src/build/generateSceneManifest.js";
4
5
  import { buildSwiftTUIWebApp } from "./src/build/buildSwiftTUIWebApp.js";
5
- export { buildAppWasm, buildSwiftTUIWebApp, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
6
+ export { buildAppWasm, buildSwiftTUIWebApp, copyDomFontAssets, defaultInitialMemory, defaultMaxMemory, defaultStackSize, defaultWasmSwiftSDK, formatCommandForLogs, generateSceneManifest, hasRequiredWasmFlags, packageBrowserValidatedWasm, requiredWasmSwiftFlags, resolveSwiftArtifacts, wasmBuildConfigurationLogLines };
@@ -1 +1 @@
1
- {"version":3,"file":"buildAppWasm.js","names":[],"sources":["../../../src/build/buildAppWasm.ts"],"sourcesContent":["import { mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { optimizePackagedWasm } from \"./optimizePackagedWasm.ts\";\nimport {\n resolveSwiftArtifacts,\n type ResolveSwiftArtifactsOptions,\n type SwiftArtifactPaths,\n type WasmBuildConfiguration,\n} from \"./resolveSwiftArtifacts.ts\";\nimport { stripPackagedWasm } from \"./stripPackagedWasm.ts\";\nimport { formatWasmTypeDiagnostics } from \"./wasmTypeDiagnostics.ts\";\n\nexport interface BuildAppWasmOptions extends ResolveSwiftArtifactsOptions {\n configuration?: WasmBuildConfiguration;\n packagePath: string;\n outputDirectory: string;\n product: string;\n}\n\nexport async function buildAppWasm(\n options: BuildAppWasmOptions\n): Promise<SwiftArtifactPaths> {\n const artifacts = await resolveSwiftArtifacts(options);\n\n const packagedWasmPath = join(options.outputDirectory, \"assets\", \"app.wasm\");\n await mkdir(join(options.outputDirectory, \"assets\"), { recursive: true });\n await rm(packagedWasmPath, { force: true });\n await packageBrowserValidatedWasm({\n sourceWasmPath: artifacts.wasmPath,\n outputWasmPath: packagedWasmPath,\n });\n return artifacts;\n}\n\ninterface PackageBrowserValidatedWasmOptions {\n optimize?: (wasmPath: string) => Promise<void>;\n sourceWasmPath: string;\n outputWasmPath: string;\n strip?: (wasmPath: string) => Promise<void>;\n onWarning?: (message: string) => void;\n}\n\nexport async function packageBrowserValidatedWasm(\n options: PackageBrowserValidatedWasmOptions\n): Promise<void> {\n const sourceBytes = await readFile(options.sourceWasmPath);\n await writeFile(options.outputWasmPath, sourceBytes);\n\n // Track the last bytes that passed browser validation and are on disk, so a\n // later stage failure restores the best validated output rather than the raw\n // source (discarding an earlier successful optimize pass).\n let lastGood = sourceBytes;\n\n const optimize = options.optimize ?? optimizePackagedWasm;\n try {\n await optimize(options.outputWasmPath);\n await validateBrowserWasm(options.outputWasmPath, \"optimized wasm\");\n lastGood = await readFile(options.outputWasmPath);\n } catch (error) {\n await writeFile(options.outputWasmPath, sourceBytes);\n const message = error instanceof Error ? error.message : String(error);\n\n try {\n await validateBrowserWasm(options.outputWasmPath, \"generated wasm\");\n } catch (rawError) {\n const rawMessage = rawError instanceof Error ? rawError.message : String(rawError);\n throw new Error([\n rawMessage,\n `wasm optimization step failed: ${message}`,\n ].join(\"\\n\"));\n }\n\n const warning = [\n `warning: keeping unoptimized wasm at ${options.outputWasmPath}`,\n `wasm optimization step failed or did not produce browser-parseable output: ${message}`,\n ].join(\"\\n\");\n (options.onWarning ?? console.warn)(warning);\n }\n\n const strip = options.strip ?? stripPackagedWasm;\n\n try {\n await strip(options.outputWasmPath);\n await validateBrowserWasm(options.outputWasmPath, \"stripped wasm\");\n } catch (error) {\n // Stripping is a size optimization only. Restore the last validated wasm\n // (the optimized bytes when optimization succeeded, otherwise the raw\n // source) whenever toolchain-specific objcopy output fails browser\n // validation, rather than discarding a successful optimize pass.\n await writeFile(options.outputWasmPath, lastGood);\n const message = error instanceof Error ? error.message : String(error);\n const warning = [\n `warning: keeping unstripped wasm at ${options.outputWasmPath}`,\n `strip step failed browser validation or tooling requirements: ${message}`,\n ].join(\"\\n\");\n (options.onWarning ?? console.warn)(warning);\n }\n}\n\nasync function validateBrowserWasm(\n wasmPath: string,\n description: string\n): Promise<void> {\n const bytes = await readFile(wasmPath);\n try {\n // Validate against the same JS API the browser uses before we publish it.\n await WebAssembly.compile(bytes);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error([\n `${description} does not parse in browser WebAssembly (${wasmPath}): ${message}`,\n formatWasmTypeDiagnostics(bytes),\n ].join(\"\\n\"));\n }\n}\n"],"mappings":";;;;;;;AAmBA,eAAsB,aACpB,SAC6B;CAC7B,MAAM,YAAY,MAAM,sBAAsB,OAAO;CAErD,MAAM,mBAAmB,KAAK,QAAQ,iBAAiB,UAAU,UAAU;CAC3E,MAAM,MAAM,KAAK,QAAQ,iBAAiB,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CACxE,MAAM,GAAG,kBAAkB,EAAE,OAAO,KAAK,CAAC;CAC1C,MAAM,4BAA4B;EAChC,gBAAgB,UAAU;EAC1B,gBAAgB;CAClB,CAAC;CACD,OAAO;AACT;AAUA,eAAsB,4BACpB,SACe;CACf,MAAM,cAAc,MAAM,SAAS,QAAQ,cAAc;CACzD,MAAM,UAAU,QAAQ,gBAAgB,WAAW;CAKnD,IAAI,WAAW;CAEf,MAAM,WAAW,QAAQ,YAAY;CACrC,IAAI;EACF,MAAM,SAAS,QAAQ,cAAc;EACrC,MAAM,oBAAoB,QAAQ,gBAAgB,gBAAgB;EAClE,WAAW,MAAM,SAAS,QAAQ,cAAc;CAClD,SAAS,OAAO;EACd,MAAM,UAAU,QAAQ,gBAAgB,WAAW;EACnD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAErE,IAAI;GACF,MAAM,oBAAoB,QAAQ,gBAAgB,gBAAgB;EACpE,SAAS,UAAU;GACjB,MAAM,aAAa,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ;GACjF,MAAM,IAAI,MAAM,CACd,YACA,kCAAkC,SACpC,CAAC,CAAC,KAAK,IAAI,CAAC;EACd;EAEA,MAAM,UAAU,CACd,wCAAwC,QAAQ,kBAChD,8EAA8E,SAChF,CAAC,CAAC,KAAK,IAAI;EACX,CAAC,QAAQ,aAAa,QAAQ,KAAA,CAAM,OAAO;CAC7C;CAEA,MAAM,QAAQ,QAAQ,SAAS;CAE/B,IAAI;EACF,MAAM,MAAM,QAAQ,cAAc;EAClC,MAAM,oBAAoB,QAAQ,gBAAgB,eAAe;CACnE,SAAS,OAAO;EAKd,MAAM,UAAU,QAAQ,gBAAgB,QAAQ;EAChD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,UAAU,CACd,uCAAuC,QAAQ,kBAC/C,iEAAiE,SACnE,CAAC,CAAC,KAAK,IAAI;EACX,CAAC,QAAQ,aAAa,QAAQ,KAAA,CAAM,OAAO;CAC7C;AACF;AAEA,eAAe,oBACb,UACA,aACe;CACf,MAAM,QAAQ,MAAM,SAAS,QAAQ;CACrC,IAAI;EAEF,MAAM,YAAY,QAAQ,KAAK;CACjC,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,IAAI,MAAM,CACd,GAAG,YAAY,0CAA0C,SAAS,KAAK,WACvE,0BAA0B,KAAK,CACjC,CAAC,CAAC,KAAK,IAAI,CAAC;CACd;AACF"}
1
+ {"version":3,"file":"buildAppWasm.js","names":[],"sources":["../../../src/build/buildAppWasm.ts"],"sourcesContent":["import { mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { optimizePackagedWasm } from \"./optimizePackagedWasm.ts\";\nimport {\n type ResolveSwiftArtifactsOptions,\n resolveSwiftArtifacts,\n type SwiftArtifactPaths,\n type WasmBuildConfiguration,\n} from \"./resolveSwiftArtifacts.ts\";\nimport { stripPackagedWasm } from \"./stripPackagedWasm.ts\";\nimport { formatWasmTypeDiagnostics } from \"./wasmTypeDiagnostics.ts\";\n\nexport interface BuildAppWasmOptions extends ResolveSwiftArtifactsOptions {\n configuration?: WasmBuildConfiguration;\n packagePath: string;\n outputDirectory: string;\n product: string;\n}\n\nexport async function buildAppWasm(\n options: BuildAppWasmOptions,\n): Promise<SwiftArtifactPaths> {\n const artifacts = await resolveSwiftArtifacts(options);\n\n const packagedWasmPath = join(options.outputDirectory, \"assets\", \"app.wasm\");\n await mkdir(join(options.outputDirectory, \"assets\"), { recursive: true });\n await rm(packagedWasmPath, { force: true });\n await packageBrowserValidatedWasm({\n sourceWasmPath: artifacts.wasmPath,\n outputWasmPath: packagedWasmPath,\n });\n return artifacts;\n}\n\ninterface PackageBrowserValidatedWasmOptions {\n optimize?: (wasmPath: string) => Promise<void>;\n sourceWasmPath: string;\n outputWasmPath: string;\n strip?: (wasmPath: string) => Promise<void>;\n onWarning?: (message: string) => void;\n}\n\nexport async function packageBrowserValidatedWasm(\n options: PackageBrowserValidatedWasmOptions,\n): Promise<void> {\n const sourceBytes = await readFile(options.sourceWasmPath);\n await writeFile(options.outputWasmPath, sourceBytes);\n\n // Track the last bytes that passed browser validation and are on disk, so a\n // later stage failure restores the best validated output rather than the raw\n // source (discarding an earlier successful optimize pass).\n let lastGood = sourceBytes;\n\n const optimize = options.optimize ?? optimizePackagedWasm;\n try {\n await optimize(options.outputWasmPath);\n await validateBrowserWasm(options.outputWasmPath, \"optimized wasm\");\n lastGood = await readFile(options.outputWasmPath);\n } catch (error) {\n await writeFile(options.outputWasmPath, sourceBytes);\n const message = error instanceof Error ? error.message : String(error);\n\n try {\n await validateBrowserWasm(options.outputWasmPath, \"generated wasm\");\n } catch (rawError) {\n const rawMessage =\n rawError instanceof Error ? rawError.message : String(rawError);\n throw new Error(\n [rawMessage, `wasm optimization step failed: ${message}`].join(\"\\n\"),\n );\n }\n\n const warning = [\n `warning: keeping unoptimized wasm at ${options.outputWasmPath}`,\n `wasm optimization step failed or did not produce browser-parseable output: ${message}`,\n ].join(\"\\n\");\n (options.onWarning ?? console.warn)(warning);\n }\n\n const strip = options.strip ?? stripPackagedWasm;\n\n try {\n await strip(options.outputWasmPath);\n await validateBrowserWasm(options.outputWasmPath, \"stripped wasm\");\n } catch (error) {\n // Stripping is a size optimization only. Restore the last validated wasm\n // (the optimized bytes when optimization succeeded, otherwise the raw\n // source) whenever toolchain-specific objcopy output fails browser\n // validation, rather than discarding a successful optimize pass.\n await writeFile(options.outputWasmPath, lastGood);\n const message = error instanceof Error ? error.message : String(error);\n const warning = [\n `warning: keeping unstripped wasm at ${options.outputWasmPath}`,\n `strip step failed browser validation or tooling requirements: ${message}`,\n ].join(\"\\n\");\n (options.onWarning ?? console.warn)(warning);\n }\n}\n\nasync function validateBrowserWasm(\n wasmPath: string,\n description: string,\n): Promise<void> {\n const bytes = await readFile(wasmPath);\n try {\n // Validate against the same JS API the browser uses before we publish it.\n await WebAssembly.compile(bytes);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `${description} does not parse in browser WebAssembly (${wasmPath}): ${message}`,\n formatWasmTypeDiagnostics(bytes),\n ].join(\"\\n\"),\n );\n }\n}\n"],"mappings":";;;;;;;AAmBA,eAAsB,aACpB,SAC6B;CAC7B,MAAM,YAAY,MAAM,sBAAsB,OAAO;CAErD,MAAM,mBAAmB,KAAK,QAAQ,iBAAiB,UAAU,UAAU;CAC3E,MAAM,MAAM,KAAK,QAAQ,iBAAiB,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CACxE,MAAM,GAAG,kBAAkB,EAAE,OAAO,KAAK,CAAC;CAC1C,MAAM,4BAA4B;EAChC,gBAAgB,UAAU;EAC1B,gBAAgB;CAClB,CAAC;CACD,OAAO;AACT;AAUA,eAAsB,4BACpB,SACe;CACf,MAAM,cAAc,MAAM,SAAS,QAAQ,cAAc;CACzD,MAAM,UAAU,QAAQ,gBAAgB,WAAW;CAKnD,IAAI,WAAW;CAEf,MAAM,WAAW,QAAQ,YAAY;CACrC,IAAI;EACF,MAAM,SAAS,QAAQ,cAAc;EACrC,MAAM,oBAAoB,QAAQ,gBAAgB,gBAAgB;EAClE,WAAW,MAAM,SAAS,QAAQ,cAAc;CAClD,SAAS,OAAO;EACd,MAAM,UAAU,QAAQ,gBAAgB,WAAW;EACnD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAErE,IAAI;GACF,MAAM,oBAAoB,QAAQ,gBAAgB,gBAAgB;EACpE,SAAS,UAAU;GACjB,MAAM,aACJ,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ;GAChE,MAAM,IAAI,MACR,CAAC,YAAY,kCAAkC,SAAS,CAAC,CAAC,KAAK,IAAI,CACrE;EACF;EAEA,MAAM,UAAU,CACd,wCAAwC,QAAQ,kBAChD,8EAA8E,SAChF,CAAC,CAAC,KAAK,IAAI;EACX,CAAC,QAAQ,aAAa,QAAQ,KAAA,CAAM,OAAO;CAC7C;CAEA,MAAM,QAAQ,QAAQ,SAAS;CAE/B,IAAI;EACF,MAAM,MAAM,QAAQ,cAAc;EAClC,MAAM,oBAAoB,QAAQ,gBAAgB,eAAe;CACnE,SAAS,OAAO;EAKd,MAAM,UAAU,QAAQ,gBAAgB,QAAQ;EAChD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,UAAU,CACd,uCAAuC,QAAQ,kBAC/C,iEAAiE,SACnE,CAAC,CAAC,KAAK,IAAI;EACX,CAAC,QAAQ,aAAa,QAAQ,KAAA,CAAM,OAAO;CAC7C;AACF;AAEA,eAAe,oBACb,UACA,aACe;CACf,MAAM,QAAQ,MAAM,SAAS,QAAQ;CACrC,IAAI;EAEF,MAAM,YAAY,QAAQ,KAAK;CACjC,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,MAAM,IAAI,MACR,CACE,GAAG,YAAY,0CAA0C,SAAS,KAAK,WACvE,0BAA0B,KAAK,CACjC,CAAC,CAAC,KAAK,IAAI,CACb;CACF;AACF"}
@@ -1,4 +1,5 @@
1
1
  import { buildAppWasm } from "./buildAppWasm.js";
2
+ import { copyDomFontAssets } from "./copyDomFontAssets.js";
2
3
  import { generateSceneManifest } from "./generateSceneManifest.js";
3
4
  import { mkdir, rm } from "node:fs/promises";
4
5
  import { join } from "node:path";
@@ -16,6 +17,7 @@ async function buildSwiftTUIWebApp(options) {
16
17
  swiftCommand: options.swiftCommand
17
18
  });
18
19
  await buildAppWasm(options);
20
+ await copyDomFontAssets(options.outputDirectory);
19
21
  }
20
22
  //#endregion
21
23
  export { buildSwiftTUIWebApp };
@@ -1 +1 @@
1
- {"version":3,"file":"buildSwiftTUIWebApp.js","names":[],"sources":["../../../src/build/buildSwiftTUIWebApp.ts"],"sourcesContent":["import { mkdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { buildAppWasm, type BuildAppWasmOptions } from \"./buildAppWasm.ts\";\nimport { generateSceneManifest } from \"./generateSceneManifest.ts\";\n\nexport interface BuildSwiftTUIWebAppOptions extends BuildAppWasmOptions {\n appExecutable?: string;\n}\n\nexport async function buildSwiftTUIWebApp(\n options: BuildSwiftTUIWebAppOptions\n): Promise<void> {\n await rm(options.outputDirectory, { recursive: true, force: true });\n await mkdir(options.outputDirectory, { recursive: true });\n await generateSceneManifest({\n packagePath: options.packagePath,\n outputPath: join(options.outputDirectory, \"scene-manifest.json\"),\n appExecutable: options.appExecutable ?? options.product,\n swiftCommand: options.swiftCommand,\n });\n await buildAppWasm(options);\n}\n"],"mappings":";;;;;AASA,eAAsB,oBACpB,SACe;CACf,MAAM,GAAG,QAAQ,iBAAiB;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAClE,MAAM,MAAM,QAAQ,iBAAiB,EAAE,WAAW,KAAK,CAAC;CACxD,MAAM,sBAAsB;EAC1B,aAAa,QAAQ;EACrB,YAAY,KAAK,QAAQ,iBAAiB,qBAAqB;EAC/D,eAAe,QAAQ,iBAAiB,QAAQ;EAChD,cAAc,QAAQ;CACxB,CAAC;CACD,MAAM,aAAa,OAAO;AAC5B"}
1
+ {"version":3,"file":"buildSwiftTUIWebApp.js","names":[],"sources":["../../../src/build/buildSwiftTUIWebApp.ts"],"sourcesContent":["import { mkdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { type BuildAppWasmOptions, buildAppWasm } from \"./buildAppWasm.ts\";\nimport { copyDomFontAssets } from \"./copyDomFontAssets.ts\";\nimport { generateSceneManifest } from \"./generateSceneManifest.ts\";\n\nexport interface BuildSwiftTUIWebAppOptions extends BuildAppWasmOptions {\n appExecutable?: string;\n}\n\nexport async function buildSwiftTUIWebApp(\n options: BuildSwiftTUIWebAppOptions,\n): Promise<void> {\n await rm(options.outputDirectory, { recursive: true, force: true });\n await mkdir(options.outputDirectory, { recursive: true });\n await generateSceneManifest({\n packagePath: options.packagePath,\n outputPath: join(options.outputDirectory, \"scene-manifest.json\"),\n appExecutable: options.appExecutable ?? options.product,\n swiftCommand: options.swiftCommand,\n });\n await buildAppWasm(options);\n await copyDomFontAssets(options.outputDirectory);\n}\n"],"mappings":";;;;;;AAUA,eAAsB,oBACpB,SACe;CACf,MAAM,GAAG,QAAQ,iBAAiB;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAClE,MAAM,MAAM,QAAQ,iBAAiB,EAAE,WAAW,KAAK,CAAC;CACxD,MAAM,sBAAsB;EAC1B,aAAa,QAAQ;EACrB,YAAY,KAAK,QAAQ,iBAAiB,qBAAqB;EAC/D,eAAe,QAAQ,iBAAiB,QAAQ;EAChD,cAAc,QAAQ;CACxB,CAAC;CACD,MAAM,aAAa,OAAO;CAC1B,MAAM,kBAAkB,QAAQ,eAAe;AACjD"}
@@ -0,0 +1,8 @@
1
+ //#region src/build/copyDomFontAssets.d.ts
2
+ /** Copies the font bytes and licensing from the installed runtime package. */
3
+ declare function copyDomFontAssets(outputDirectory: string): Promise<{
4
+ assetPath: string;
5
+ }>;
6
+ //#endregion
7
+ export { copyDomFontAssets };
8
+ //# sourceMappingURL=copyDomFontAssets.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { copyFile, mkdir, readFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { fileURLToPath } from "node:url";
5
+ import { DOM_FONT_ASSET_PATH } from "@swifttui/web";
6
+ //#region src/build/copyDomFontAssets.ts
7
+ /** Copies the font bytes and licensing from the installed runtime package. */
8
+ async function copyDomFontAssets(outputDirectory) {
9
+ const root = dirname(fileURLToPath(import.meta.resolve("@swifttui/web/package.json")));
10
+ const manifestBytes = await readFile(join(root, "fonts/manifest.json"));
11
+ const manifest = JSON.parse(manifestBytes.toString());
12
+ const destination = join(outputDirectory, DOM_FONT_ASSET_PATH);
13
+ await mkdir(destination, { recursive: true });
14
+ for (const asset of [...manifest.faces, {
15
+ file: "LICENSE.md",
16
+ sha256: manifest.licenseSha256
17
+ }]) {
18
+ if (asset.file !== asset.file.split(/[\\/]/).at(-1)) throw new Error("Invalid font asset name");
19
+ const source = join(root, "fonts", asset.file);
20
+ const bytes = await readFile(source);
21
+ if (createHash("sha256").update(bytes).digest("hex") !== asset.sha256) throw new Error(`DOM font asset hash mismatch: ${asset.file}`);
22
+ await copyFile(source, join(destination, asset.file));
23
+ }
24
+ await copyFile(join(root, "fonts/manifest.json"), join(destination, "manifest.json"));
25
+ return { assetPath: DOM_FONT_ASSET_PATH };
26
+ }
27
+ //#endregion
28
+ export { copyDomFontAssets };
29
+
30
+ //# sourceMappingURL=copyDomFontAssets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyDomFontAssets.js","names":[],"sources":["../../../src/build/copyDomFontAssets.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { copyFile, mkdir, readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { DOM_FONT_ASSET_PATH } from \"@swifttui/web\";\n\n/** Copies the font bytes and licensing from the installed runtime package. */\nexport async function copyDomFontAssets(\n outputDirectory: string,\n): Promise<{ assetPath: string }> {\n const root = dirname(\n fileURLToPath(import.meta.resolve(\"@swifttui/web/package.json\")),\n );\n const manifestBytes = await readFile(join(root, \"fonts/manifest.json\"));\n const manifest = JSON.parse(manifestBytes.toString()) as {\n faces: { file: string; sha256: string }[];\n licenseSha256: string;\n };\n const destination = join(outputDirectory, DOM_FONT_ASSET_PATH);\n await mkdir(destination, { recursive: true });\n for (const asset of [\n ...manifest.faces,\n { file: \"LICENSE.md\", sha256: manifest.licenseSha256 },\n ]) {\n if (asset.file !== asset.file.split(/[\\\\/]/).at(-1))\n throw new Error(\"Invalid font asset name\");\n const source = join(root, \"fonts\", asset.file);\n const bytes = await readFile(source);\n if (createHash(\"sha256\").update(bytes).digest(\"hex\") !== asset.sha256)\n throw new Error(`DOM font asset hash mismatch: ${asset.file}`);\n await copyFile(source, join(destination, asset.file));\n }\n await copyFile(\n join(root, \"fonts/manifest.json\"),\n join(destination, \"manifest.json\"),\n );\n return { assetPath: DOM_FONT_ASSET_PATH };\n}\n"],"mappings":";;;;;;;AAOA,eAAsB,kBACpB,iBACgC;CAChC,MAAM,OAAO,QACX,cAAc,OAAO,KAAK,QAAQ,4BAA4B,CAAC,CACjE;CACA,MAAM,gBAAgB,MAAM,SAAS,KAAK,MAAM,qBAAqB,CAAC;CACtE,MAAM,WAAW,KAAK,MAAM,cAAc,SAAS,CAAC;CAIpD,MAAM,cAAc,KAAK,iBAAiB,mBAAmB;CAC7D,MAAM,MAAM,aAAa,EAAE,WAAW,KAAK,CAAC;CAC5C,KAAK,MAAM,SAAS,CAClB,GAAG,SAAS,OACZ;EAAE,MAAM;EAAc,QAAQ,SAAS;CAAc,CACvD,GAAG;EACD,IAAI,MAAM,SAAS,MAAM,KAAK,MAAM,OAAO,CAAC,CAAC,GAAG,EAAE,GAChD,MAAM,IAAI,MAAM,yBAAyB;EAC3C,MAAM,SAAS,KAAK,MAAM,SAAS,MAAM,IAAI;EAC7C,MAAM,QAAQ,MAAM,SAAS,MAAM;EACnC,IAAI,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,MAAM,MAAM,QAC7D,MAAM,IAAI,MAAM,iCAAiC,MAAM,MAAM;EAC/D,MAAM,SAAS,QAAQ,KAAK,aAAa,MAAM,IAAI,CAAC;CACtD;CACA,MAAM,SACJ,KAAK,MAAM,qBAAqB,GAChC,KAAK,aAAa,eAAe,CACnC;CACA,OAAO,EAAE,WAAW,oBAAoB;AAC1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"generateSceneManifest.js","names":[],"sources":["../../../src/build/generateSceneManifest.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport {\n loadWebHostSceneManifest,\n webTUISceneManifestToJSON,\n type WebHostSceneManifest,\n} from \"@swifttui/web/manifest\";\nimport { runCommand } from \"./runCommand.ts\";\nimport { swiftCommandPrefix } from \"./swiftCommandPrefix.ts\";\n\nexport interface GenerateSceneManifestOptions {\n packagePath: string;\n outputPath: string;\n appExecutable: string;\n swiftCommand?: readonly string[];\n}\n\nexport async function generateSceneManifest(\n options: GenerateSceneManifestOptions\n): Promise<WebHostSceneManifest> {\n const output = await runManifestCommand(options);\n const manifest = await loadWebHostSceneManifest(output.trim());\n await mkdir(dirname(options.outputPath), { recursive: true });\n await writeFile(options.outputPath, webTUISceneManifestToJSON(manifest));\n return manifest;\n}\n\nasync function runManifestCommand(\n options: GenerateSceneManifestOptions\n): Promise<string> {\n return await runCommand(\n [\n ...(options.swiftCommand ?? swiftCommandPrefix()),\n \"run\",\n \"--package-path\",\n options.packagePath,\n options.appExecutable,\n ],\n {\n env: {\n ...process.env,\n SWIFTTUI_MODE: \"manifest\",\n },\n }\n );\n}\n"],"mappings":";;;;;;AAiBA,eAAsB,sBACpB,SAC+B;CAE/B,MAAM,WAAW,MAAM,0BAAyB,MAD3B,mBAAmB,OAAO,EAAA,CACQ,KAAK,CAAC;CAC7D,MAAM,MAAM,QAAQ,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAC5D,MAAM,UAAU,QAAQ,YAAY,0BAA0B,QAAQ,CAAC;CACvE,OAAO;AACT;AAEA,eAAe,mBACb,SACiB;CACjB,OAAO,MAAM,WACX;EACE,GAAI,QAAQ,gBAAgB,mBAAmB;EAC/C;EACA;EACA,QAAQ;EACR,QAAQ;CACV,GACA,EACE,KAAK;EACH,GAAG,QAAQ;EACX,eAAe;CACjB,EACF,CACF;AACF"}
1
+ {"version":3,"file":"generateSceneManifest.js","names":[],"sources":["../../../src/build/generateSceneManifest.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport {\n loadWebHostSceneManifest,\n type WebHostSceneManifest,\n webTUISceneManifestToJSON,\n} from \"@swifttui/web/manifest\";\nimport { runCommand } from \"./runCommand.ts\";\nimport { swiftCommandPrefix } from \"./swiftCommandPrefix.ts\";\n\nexport interface GenerateSceneManifestOptions {\n packagePath: string;\n outputPath: string;\n appExecutable: string;\n swiftCommand?: readonly string[];\n}\n\nexport async function generateSceneManifest(\n options: GenerateSceneManifestOptions,\n): Promise<WebHostSceneManifest> {\n const output = await runManifestCommand(options);\n const manifest = await loadWebHostSceneManifest(output.trim());\n await mkdir(dirname(options.outputPath), { recursive: true });\n await writeFile(options.outputPath, webTUISceneManifestToJSON(manifest));\n return manifest;\n}\n\nasync function runManifestCommand(\n options: GenerateSceneManifestOptions,\n): Promise<string> {\n return await runCommand(\n [\n ...(options.swiftCommand ?? swiftCommandPrefix()),\n \"run\",\n \"--package-path\",\n options.packagePath,\n options.appExecutable,\n ],\n {\n env: {\n ...process.env,\n SWIFTTUI_MODE: \"manifest\",\n },\n },\n );\n}\n"],"mappings":";;;;;;AAiBA,eAAsB,sBACpB,SAC+B;CAE/B,MAAM,WAAW,MAAM,0BAAyB,MAD3B,mBAAmB,OAAO,EAAA,CACQ,KAAK,CAAC;CAC7D,MAAM,MAAM,QAAQ,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAC5D,MAAM,UAAU,QAAQ,YAAY,0BAA0B,QAAQ,CAAC;CACvE,OAAO;AACT;AAEA,eAAe,mBACb,SACiB;CACjB,OAAO,MAAM,WACX;EACE,GAAI,QAAQ,gBAAgB,mBAAmB;EAC/C;EACA;EACA,QAAQ;EACR,QAAQ;CACV,GACA,EACE,KAAK;EACH,GAAG,QAAQ;EACX,eAAe;CACjB,EACF,CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"optimizePackagedWasm.js","names":[],"sources":["../../../src/build/optimizePackagedWasm.ts"],"sourcesContent":["import { findExecutable, runCommand } from \"./runCommand.ts\";\n\nexport async function optimizePackagedWasm(\n wasmPath: string\n): Promise<void> {\n const wasmOptPath = findExecutable(\"wasm-opt\");\n if (!wasmOptPath) {\n throw new Error(\n \"missing wasm-opt in PATH; install Binaryen so wasm packaging is deterministic across environments\"\n );\n }\n\n await runCommand([\n wasmOptPath,\n \"-Os\",\n wasmPath,\n \"-o\",\n wasmPath,\n ]);\n}\n"],"mappings":";;AAEA,eAAsB,qBACpB,UACe;CACf,MAAM,cAAc,eAAe,UAAU;CAC7C,IAAI,CAAC,aACH,MAAM,IAAI,MACR,mGACF;CAGF,MAAM,WAAW;EACf;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"optimizePackagedWasm.js","names":[],"sources":["../../../src/build/optimizePackagedWasm.ts"],"sourcesContent":["import { findExecutable, runCommand } from \"./runCommand.ts\";\n\nexport async function optimizePackagedWasm(wasmPath: string): Promise<void> {\n const wasmOptPath = findExecutable(\"wasm-opt\");\n if (!wasmOptPath) {\n throw new Error(\n \"missing wasm-opt in PATH; install Binaryen so wasm packaging is deterministic across environments\",\n );\n }\n\n await runCommand([wasmOptPath, \"-Os\", wasmPath, \"-o\", wasmPath]);\n}\n"],"mappings":";;AAEA,eAAsB,qBAAqB,UAAiC;CAC1E,MAAM,cAAc,eAAe,UAAU;CAC7C,IAAI,CAAC,aACH,MAAM,IAAI,MACR,mGACF;CAGF,MAAM,WAAW;EAAC;EAAa;EAAO;EAAU;EAAM;CAAQ,CAAC;AACjE"}
@@ -123,7 +123,7 @@ function formatCommandForLogs(args) {
123
123
  return args.map(shellQuote).join(" ");
124
124
  }
125
125
  function containsSubsequence(args, expected) {
126
- if (expected.length == 0) return true;
126
+ if (expected.length === 0) return true;
127
127
  for (let index = 0; index <= args.length - expected.length; index += 1) {
128
128
  let matches = true;
129
129
  for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex += 1) if (args[index + expectedIndex] !== expected[expectedIndex]) {
@@ -1 +1 @@
1
- {"version":3,"file":"resolveSwiftArtifacts.js","names":[],"sources":["../../../src/build/resolveSwiftArtifacts.ts"],"sourcesContent":["import { access } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { runCommand } from \"./runCommand.ts\";\nimport { swiftCommandPrefix } from \"./swiftCommandPrefix.ts\";\n\nexport interface ResolveSwiftArtifactsOptions {\n configuration?: WasmBuildConfiguration;\n extraLinkerFlags?: readonly string[];\n extraSwiftBuildArgs?: readonly string[];\n extraSwiftcFlags?: readonly string[];\n initialMemory?: number | string;\n maxMemory?: number | string;\n packagePath: string;\n product: string;\n stackSize?: number | string;\n swiftCommand?: readonly string[];\n swiftSDK?: string;\n}\n\nexport type WasmBuildConfiguration = \"debug\" | \"release\";\n\nexport interface SwiftArtifactPaths {\n binPath: string;\n wasmPath: string;\n}\n\nexport const requiredWasmSwiftFlags = [\n \"-Xswiftc\",\n \"-Osize\",\n \"-Xswiftc\",\n \"-Xfrontend\",\n \"-Xswiftc\",\n \"-disable-llvm-merge-functions-pass\",\n] as const;\n\n// Must track the toolchain pinned in the repo root's `.swift-version`: CI\n// runners install only the wasm SDK matching that version, so a stale id here\n// fails to resolve on a clean runner while still working on any machine that\n// still has the older SDK installed. `resolveSwiftArtifacts.test.ts` pins the\n// two together.\nexport const defaultWasmSwiftSDK = \"swift-6.4.0-RELEASE_wasm\";\nexport const defaultInitialMemory = \"536870912\";\nexport const defaultMaxMemory = \"4294967296\";\n// 16 MiB: the resolve descent's linear-memory (shadow) stack usage scales\n// with view-tree depth, and the non-lean profile's deep scenes measurably\n// overflow a 1 MiB stack (wasm \"memory access out of bounds\" at steady\n// state). The reservation is virtual against a 512 MiB initial memory.\nexport const defaultStackSize = \"16777216\";\n\nexport async function resolveSwiftArtifacts(\n options: ResolveSwiftArtifactsOptions\n): Promise<SwiftArtifactPaths> {\n const configuration = options.configuration ?? \"release\";\n const swiftlyWorkingDirectory = await resolveSwiftlyWorkingDirectory(options.packagePath);\n const swiftCommand = [...(options.swiftCommand ?? swiftCommandPrefix())];\n const environment = {\n ...process.env\n };\n\n // The browser WebAssembly API rejects function types with more than 1000\n // parameters. Swift's wasm release builds can trip that limit when LLVM's\n // merge-functions pass combines large outlined-copy helpers. `-Osize` helps,\n // but some Darwin CI runners still reproduce the failure unless we also\n // disable that merge pass explicitly.\n const swiftBuildArgs = [\n \"build\",\n \"--package-path\",\n options.packagePath,\n \"--swift-sdk\",\n options.swiftSDK ?? defaultWasmSwiftSDK,\n \"-c\",\n configuration,\n ...requiredSwiftFlags(configuration),\n ...swiftcFlags(options.extraSwiftcFlags),\n \"-Xlinker\",\n `--initial-memory=${options.initialMemory ?? defaultInitialMemory}`,\n \"-Xlinker\",\n `--max-memory=${options.maxMemory ?? defaultMaxMemory}`,\n \"-Xlinker\",\n \"-z\",\n \"-Xlinker\",\n `stack-size=${options.stackSize ?? defaultStackSize}`,\n ...linkerFlags(options.extraLinkerFlags),\n ...(options.extraSwiftBuildArgs ?? []),\n ];\n\n if (configuration === \"release\") {\n confirmRequiredWasmFlags(swiftBuildArgs);\n }\n\n const buildCommand = [\n ...swiftCommand,\n ...swiftBuildArgs,\n \"--product\",\n options.product,\n ];\n const showBinPathCommand = [\n ...swiftCommand,\n ...swiftBuildArgs,\n \"--show-bin-path\",\n ];\n\n logWasmBuildConfiguration({\n configuration,\n packagePath: options.packagePath,\n product: options.product,\n swiftlyWorkingDirectory,\n buildCommand,\n showBinPathCommand,\n });\n\n await runCommand(buildCommand, {\n cwd: swiftlyWorkingDirectory,\n env: environment,\n });\n\n const binPath = await runCommand(showBinPathCommand, {\n cwd: swiftlyWorkingDirectory,\n env: environment,\n });\n\n const wasmPath = join(binPath.trim(), `${options.product}.wasm`);\n return {\n binPath: binPath.trim(),\n wasmPath,\n };\n}\n\ninterface WasmBuildConfigurationLog {\n configuration?: WasmBuildConfiguration;\n packagePath: string;\n product: string;\n swiftlyWorkingDirectory: string;\n buildCommand: string[];\n showBinPathCommand: string[];\n}\n\nexport function hasRequiredWasmFlags(args: readonly string[]): boolean {\n return containsSubsequence(args, requiredWasmSwiftFlags);\n}\n\nfunction confirmRequiredWasmFlags(args: readonly string[]): void {\n if (hasRequiredWasmFlags(args)) {\n return;\n }\n\n throw new Error(\n `missing required wasm Swift flags: ${requiredWasmSwiftFlags.join(\" \")}`\n );\n}\n\nfunction requiredSwiftFlags(configuration: WasmBuildConfiguration): readonly string[] {\n switch (configuration) {\n case \"debug\":\n return [];\n case \"release\":\n return requiredWasmSwiftFlags;\n }\n}\n\nfunction swiftcFlags(flags: readonly string[] | undefined): string[] {\n return (flags ?? []).flatMap((flag) => [\"-Xswiftc\", flag]);\n}\n\nfunction linkerFlags(flags: readonly string[] | undefined): string[] {\n return (flags ?? []).flatMap((flag) => [\"-Xlinker\", flag]);\n}\n\nfunction logWasmBuildConfiguration(config: WasmBuildConfigurationLog): void {\n for (const line of wasmBuildConfigurationLogLines(config)) {\n console.error(line);\n }\n}\n\nexport function wasmBuildConfigurationLogLines(\n config: WasmBuildConfigurationLog\n): string[] {\n const configuration = config.configuration ?? \"release\";\n return [\n `WASM_BUILD_CONFIGURATION_NAME=${configuration}`,\n `WASM_REQUIRED_FLAGS_CONFIRMED=${configuration === \"release\" ? \"true\" : \"skipped\"}`,\n `WASM_REQUIRED_FLAGS=${requiredWasmSwiftFlags.join(\" \")}`,\n `WASM_REQUIRED_FLAGS_JSON=${JSON.stringify([...requiredWasmSwiftFlags])}`,\n `WASM_BUILD_COMMAND=${formatCommandForLogs(config.buildCommand)}`,\n `WASM_BUILD_COMMAND_ARGS_JSON=${JSON.stringify(config.buildCommand)}`,\n `WASM_SHOW_BIN_PATH_COMMAND=${formatCommandForLogs(config.showBinPathCommand)}`,\n `WASM_SHOW_BIN_PATH_COMMAND_ARGS_JSON=${JSON.stringify(config.showBinPathCommand)}`,\n `WASM_BUILD_CONFIGURATION ${JSON.stringify({\n packagePath: config.packagePath,\n product: config.product,\n configuration,\n swiftlyWorkingDirectory: config.swiftlyWorkingDirectory,\n requiredFlags: [...requiredWasmSwiftFlags],\n buildCommand: formatCommandForLogs(config.buildCommand),\n showBinPathCommand: formatCommandForLogs(config.showBinPathCommand),\n })}`,\n ];\n}\n\nexport function formatCommandForLogs(args: readonly string[]): string {\n return args.map(shellQuote).join(\" \");\n}\n\nfunction containsSubsequence(\n args: readonly string[],\n expected: readonly string[]\n): boolean {\n if (expected.length == 0) {\n return true;\n }\n\n for (let index = 0; index <= args.length - expected.length; index += 1) {\n let matches = true;\n for (let expectedIndex = 0; expectedIndex < expected.length; expectedIndex += 1) {\n if (args[index + expectedIndex] !== expected[expectedIndex]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction shellQuote(arg: string): string {\n if (/^[A-Za-z0-9_./:=+-]+$/.test(arg)) {\n return arg;\n }\n\n return `'${arg.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\nasync function resolveSwiftlyWorkingDirectory(\n startPath: string\n): Promise<string> {\n let currentPath = resolve(startPath);\n\n while (true) {\n if (await fileExists(join(currentPath, \".swift-version\"))) {\n return currentPath;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n return resolve(startPath);\n }\n\n currentPath = parentPath;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"resolveSwiftArtifacts.js","names":[],"sources":["../../../src/build/resolveSwiftArtifacts.ts"],"sourcesContent":["import { access } from \"node:fs/promises\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { runCommand } from \"./runCommand.ts\";\nimport { swiftCommandPrefix } from \"./swiftCommandPrefix.ts\";\n\nexport interface ResolveSwiftArtifactsOptions {\n configuration?: WasmBuildConfiguration;\n extraLinkerFlags?: readonly string[];\n extraSwiftBuildArgs?: readonly string[];\n extraSwiftcFlags?: readonly string[];\n initialMemory?: number | string;\n maxMemory?: number | string;\n packagePath: string;\n product: string;\n stackSize?: number | string;\n swiftCommand?: readonly string[];\n swiftSDK?: string;\n}\n\nexport type WasmBuildConfiguration = \"debug\" | \"release\";\n\nexport interface SwiftArtifactPaths {\n binPath: string;\n wasmPath: string;\n}\n\nexport const requiredWasmSwiftFlags = [\n \"-Xswiftc\",\n \"-Osize\",\n \"-Xswiftc\",\n \"-Xfrontend\",\n \"-Xswiftc\",\n \"-disable-llvm-merge-functions-pass\",\n] as const;\n\n// Must track the toolchain pinned in the repo root's `.swift-version`: CI\n// runners install only the wasm SDK matching that version, so a stale id here\n// fails to resolve on a clean runner while still working on any machine that\n// still has the older SDK installed. `resolveSwiftArtifacts.test.ts` pins the\n// two together.\nexport const defaultWasmSwiftSDK = \"swift-6.4.0-RELEASE_wasm\";\nexport const defaultInitialMemory = \"536870912\";\nexport const defaultMaxMemory = \"4294967296\";\n// 16 MiB: the resolve descent's linear-memory (shadow) stack usage scales\n// with view-tree depth, and the non-lean profile's deep scenes measurably\n// overflow a 1 MiB stack (wasm \"memory access out of bounds\" at steady\n// state). The reservation is virtual against a 512 MiB initial memory.\nexport const defaultStackSize = \"16777216\";\n\nexport async function resolveSwiftArtifacts(\n options: ResolveSwiftArtifactsOptions,\n): Promise<SwiftArtifactPaths> {\n const configuration = options.configuration ?? \"release\";\n const swiftlyWorkingDirectory = await resolveSwiftlyWorkingDirectory(\n options.packagePath,\n );\n const swiftCommand = [...(options.swiftCommand ?? swiftCommandPrefix())];\n const environment = {\n ...process.env,\n };\n\n // The browser WebAssembly API rejects function types with more than 1000\n // parameters. Swift's wasm release builds can trip that limit when LLVM's\n // merge-functions pass combines large outlined-copy helpers. `-Osize` helps,\n // but some Darwin CI runners still reproduce the failure unless we also\n // disable that merge pass explicitly.\n const swiftBuildArgs = [\n \"build\",\n \"--package-path\",\n options.packagePath,\n \"--swift-sdk\",\n options.swiftSDK ?? defaultWasmSwiftSDK,\n \"-c\",\n configuration,\n ...requiredSwiftFlags(configuration),\n ...swiftcFlags(options.extraSwiftcFlags),\n \"-Xlinker\",\n `--initial-memory=${options.initialMemory ?? defaultInitialMemory}`,\n \"-Xlinker\",\n `--max-memory=${options.maxMemory ?? defaultMaxMemory}`,\n \"-Xlinker\",\n \"-z\",\n \"-Xlinker\",\n `stack-size=${options.stackSize ?? defaultStackSize}`,\n ...linkerFlags(options.extraLinkerFlags),\n ...(options.extraSwiftBuildArgs ?? []),\n ];\n\n if (configuration === \"release\") {\n confirmRequiredWasmFlags(swiftBuildArgs);\n }\n\n const buildCommand = [\n ...swiftCommand,\n ...swiftBuildArgs,\n \"--product\",\n options.product,\n ];\n const showBinPathCommand = [\n ...swiftCommand,\n ...swiftBuildArgs,\n \"--show-bin-path\",\n ];\n\n logWasmBuildConfiguration({\n configuration,\n packagePath: options.packagePath,\n product: options.product,\n swiftlyWorkingDirectory,\n buildCommand,\n showBinPathCommand,\n });\n\n await runCommand(buildCommand, {\n cwd: swiftlyWorkingDirectory,\n env: environment,\n });\n\n const binPath = await runCommand(showBinPathCommand, {\n cwd: swiftlyWorkingDirectory,\n env: environment,\n });\n\n const wasmPath = join(binPath.trim(), `${options.product}.wasm`);\n return {\n binPath: binPath.trim(),\n wasmPath,\n };\n}\n\ninterface WasmBuildConfigurationLog {\n configuration?: WasmBuildConfiguration;\n packagePath: string;\n product: string;\n swiftlyWorkingDirectory: string;\n buildCommand: string[];\n showBinPathCommand: string[];\n}\n\nexport function hasRequiredWasmFlags(args: readonly string[]): boolean {\n return containsSubsequence(args, requiredWasmSwiftFlags);\n}\n\nfunction confirmRequiredWasmFlags(args: readonly string[]): void {\n if (hasRequiredWasmFlags(args)) {\n return;\n }\n\n throw new Error(\n `missing required wasm Swift flags: ${requiredWasmSwiftFlags.join(\" \")}`,\n );\n}\n\nfunction requiredSwiftFlags(\n configuration: WasmBuildConfiguration,\n): readonly string[] {\n switch (configuration) {\n case \"debug\":\n return [];\n case \"release\":\n return requiredWasmSwiftFlags;\n }\n}\n\nfunction swiftcFlags(flags: readonly string[] | undefined): string[] {\n return (flags ?? []).flatMap((flag) => [\"-Xswiftc\", flag]);\n}\n\nfunction linkerFlags(flags: readonly string[] | undefined): string[] {\n return (flags ?? []).flatMap((flag) => [\"-Xlinker\", flag]);\n}\n\nfunction logWasmBuildConfiguration(config: WasmBuildConfigurationLog): void {\n for (const line of wasmBuildConfigurationLogLines(config)) {\n console.error(line);\n }\n}\n\nexport function wasmBuildConfigurationLogLines(\n config: WasmBuildConfigurationLog,\n): string[] {\n const configuration = config.configuration ?? \"release\";\n return [\n `WASM_BUILD_CONFIGURATION_NAME=${configuration}`,\n `WASM_REQUIRED_FLAGS_CONFIRMED=${configuration === \"release\" ? \"true\" : \"skipped\"}`,\n `WASM_REQUIRED_FLAGS=${requiredWasmSwiftFlags.join(\" \")}`,\n `WASM_REQUIRED_FLAGS_JSON=${JSON.stringify([...requiredWasmSwiftFlags])}`,\n `WASM_BUILD_COMMAND=${formatCommandForLogs(config.buildCommand)}`,\n `WASM_BUILD_COMMAND_ARGS_JSON=${JSON.stringify(config.buildCommand)}`,\n `WASM_SHOW_BIN_PATH_COMMAND=${formatCommandForLogs(config.showBinPathCommand)}`,\n `WASM_SHOW_BIN_PATH_COMMAND_ARGS_JSON=${JSON.stringify(config.showBinPathCommand)}`,\n `WASM_BUILD_CONFIGURATION ${JSON.stringify({\n packagePath: config.packagePath,\n product: config.product,\n configuration,\n swiftlyWorkingDirectory: config.swiftlyWorkingDirectory,\n requiredFlags: [...requiredWasmSwiftFlags],\n buildCommand: formatCommandForLogs(config.buildCommand),\n showBinPathCommand: formatCommandForLogs(config.showBinPathCommand),\n })}`,\n ];\n}\n\nexport function formatCommandForLogs(args: readonly string[]): string {\n return args.map(shellQuote).join(\" \");\n}\n\nfunction containsSubsequence(\n args: readonly string[],\n expected: readonly string[],\n): boolean {\n if (expected.length === 0) {\n return true;\n }\n\n for (let index = 0; index <= args.length - expected.length; index += 1) {\n let matches = true;\n for (\n let expectedIndex = 0;\n expectedIndex < expected.length;\n expectedIndex += 1\n ) {\n if (args[index + expectedIndex] !== expected[expectedIndex]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction shellQuote(arg: string): string {\n if (/^[A-Za-z0-9_./:=+-]+$/.test(arg)) {\n return arg;\n }\n\n return `'${arg.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\nasync function resolveSwiftlyWorkingDirectory(\n startPath: string,\n): Promise<string> {\n let currentPath = resolve(startPath);\n\n while (true) {\n if (await fileExists(join(currentPath, \".swift-version\"))) {\n return currentPath;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n return resolve(startPath);\n }\n\n currentPath = parentPath;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { delimiter, join } from "node:path";
2
- import { accessSync } from "node:fs";
3
2
  import { spawn } from "node:child_process";
3
+ import { accessSync } from "node:fs";
4
4
  //#region src/build/runCommand.ts
5
5
  async function runCommand(cmd, options = {}) {
6
6
  const executable = cmd[0];
@@ -38,9 +38,7 @@ function findExecutable(name, pathValue = process.env.PATH) {
38
38
  try {
39
39
  accessSync(candidate);
40
40
  return candidate;
41
- } catch {
42
- continue;
43
- }
41
+ } catch {}
44
42
  }
45
43
  }
46
44
  function normalizeEnvironment(env) {
@@ -1 +1 @@
1
- {"version":3,"file":"runCommand.js","names":[],"sources":["../../../src/build/runCommand.ts"],"sourcesContent":["import { accessSync } from \"node:fs\";\nimport { delimiter, join } from \"node:path\";\nimport { spawn } from \"node:child_process\";\n\nexport interface RunCommandOptions {\n cwd?: string;\n env?: Record<string, string | undefined>;\n}\n\nexport async function runCommand(\n cmd: string[],\n options: RunCommandOptions = {}\n): Promise<string> {\n const executable = cmd[0];\n if (!executable) {\n throw new Error(\"cannot run an empty command\");\n }\n\n const proc = spawn(executable, cmd.slice(1), {\n cwd: options.cwd,\n env: normalizeEnvironment(options.env),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n const exitCode = await new Promise<number | null>((resolve, reject) => {\n proc.on(\"error\", reject);\n proc.on(\"close\", resolve);\n });\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (exitCode !== 0) {\n throw new Error([stdout, stderr].filter(Boolean).join(\"\\n\").trim() || `command failed: ${cmd.join(\" \")}`);\n }\n\n return stdout;\n}\n\nexport function findExecutable(\n name: string,\n pathValue: string | undefined = process.env.PATH\n): string | undefined {\n for (const directory of pathValue?.split(delimiter) ?? []) {\n if (!directory) {\n continue;\n }\n const candidate = join(directory, name);\n try {\n accessSync(candidate);\n return candidate;\n } catch {\n continue;\n }\n }\n return undefined;\n}\n\nfunction normalizeEnvironment(\n env: Record<string, string | undefined> | undefined\n): NodeJS.ProcessEnv | undefined {\n if (!env) {\n return undefined;\n }\n\n const normalized: NodeJS.ProcessEnv = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) {\n normalized[key] = value;\n }\n }\n return normalized;\n}\n"],"mappings":";;;;AASA,eAAsB,WACpB,KACA,UAA6B,CAAC,GACb;CACjB,MAAM,aAAa,IAAI;CACvB,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,6BAA6B;CAG/C,MAAM,OAAO,MAAM,YAAY,IAAI,MAAM,CAAC,GAAG;EAC3C,KAAK,QAAQ;EACb,KAAK,qBAAqB,QAAQ,GAAG;EACrC,OAAO;GAAC;GAAU;GAAQ;EAAM;CAClC,CAAC;CAED,MAAM,eAAyB,CAAC;CAChC,MAAM,eAAyB,CAAC;CAChC,KAAK,OAAO,GAAG,SAAS,UAAkB;EACxC,aAAa,KAAK,KAAK;CACzB,CAAC;CACD,KAAK,OAAO,GAAG,SAAS,UAAkB;EACxC,aAAa,KAAK,KAAK;CACzB,CAAC;CAED,MAAM,WAAW,MAAM,IAAI,SAAwB,SAAS,WAAW;EACrE,KAAK,GAAG,SAAS,MAAM;EACvB,KAAK,GAAG,SAAS,OAAO;CAC1B,CAAC;CACD,MAAM,SAAS,OAAO,OAAO,YAAY,CAAC,CAAC,SAAS;CACpD,MAAM,SAAS,OAAO,OAAO,YAAY,CAAC,CAAC,SAAS;CAEpD,IAAI,aAAa,GACf,MAAM,IAAI,MAAM,CAAC,QAAQ,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,mBAAmB,IAAI,KAAK,GAAG,GAAG;CAG1G,OAAO;AACT;AAEA,SAAgB,eACd,MACA,YAAgC,QAAQ,IAAI,MACxB;CACpB,KAAK,MAAM,aAAa,WAAW,MAAM,SAAS,KAAK,CAAC,GAAG;EACzD,IAAI,CAAC,WACH;EAEF,MAAM,YAAY,KAAK,WAAW,IAAI;EACtC,IAAI;GACF,WAAW,SAAS;GACpB,OAAO;EACT,QAAQ;GACN;EACF;CACF;AAEF;AAEA,SAAS,qBACP,KAC+B;CAC/B,IAAI,CAAC,KACH;CAGF,MAAM,aAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,KAAA,GACZ,WAAW,OAAO;CAGtB,OAAO;AACT"}
1
+ {"version":3,"file":"runCommand.js","names":[],"sources":["../../../src/build/runCommand.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { accessSync } from \"node:fs\";\nimport { delimiter, join } from \"node:path\";\n\nexport interface RunCommandOptions {\n cwd?: string;\n env?: Record<string, string | undefined>;\n}\n\nexport async function runCommand(\n cmd: string[],\n options: RunCommandOptions = {},\n): Promise<string> {\n const executable = cmd[0];\n if (!executable) {\n throw new Error(\"cannot run an empty command\");\n }\n\n const proc = spawn(executable, cmd.slice(1), {\n cwd: options.cwd,\n env: normalizeEnvironment(options.env),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n stdoutChunks.push(chunk);\n });\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n const exitCode = await new Promise<number | null>((resolve, reject) => {\n proc.on(\"error\", reject);\n proc.on(\"close\", resolve);\n });\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (exitCode !== 0) {\n throw new Error(\n [stdout, stderr].filter(Boolean).join(\"\\n\").trim() ||\n `command failed: ${cmd.join(\" \")}`,\n );\n }\n\n return stdout;\n}\n\nexport function findExecutable(\n name: string,\n pathValue: string | undefined = process.env.PATH,\n): string | undefined {\n for (const directory of pathValue?.split(delimiter) ?? []) {\n if (!directory) {\n continue;\n }\n const candidate = join(directory, name);\n try {\n accessSync(candidate);\n return candidate;\n } catch {}\n }\n return undefined;\n}\n\nfunction normalizeEnvironment(\n env: Record<string, string | undefined> | undefined,\n): NodeJS.ProcessEnv | undefined {\n if (!env) {\n return undefined;\n }\n\n const normalized: NodeJS.ProcessEnv = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) {\n normalized[key] = value;\n }\n }\n return normalized;\n}\n"],"mappings":";;;;AASA,eAAsB,WACpB,KACA,UAA6B,CAAC,GACb;CACjB,MAAM,aAAa,IAAI;CACvB,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,6BAA6B;CAG/C,MAAM,OAAO,MAAM,YAAY,IAAI,MAAM,CAAC,GAAG;EAC3C,KAAK,QAAQ;EACb,KAAK,qBAAqB,QAAQ,GAAG;EACrC,OAAO;GAAC;GAAU;GAAQ;EAAM;CAClC,CAAC;CAED,MAAM,eAAyB,CAAC;CAChC,MAAM,eAAyB,CAAC;CAChC,KAAK,OAAO,GAAG,SAAS,UAAkB;EACxC,aAAa,KAAK,KAAK;CACzB,CAAC;CACD,KAAK,OAAO,GAAG,SAAS,UAAkB;EACxC,aAAa,KAAK,KAAK;CACzB,CAAC;CAED,MAAM,WAAW,MAAM,IAAI,SAAwB,SAAS,WAAW;EACrE,KAAK,GAAG,SAAS,MAAM;EACvB,KAAK,GAAG,SAAS,OAAO;CAC1B,CAAC;CACD,MAAM,SAAS,OAAO,OAAO,YAAY,CAAC,CAAC,SAAS;CACpD,MAAM,SAAS,OAAO,OAAO,YAAY,CAAC,CAAC,SAAS;CAEpD,IAAI,aAAa,GACf,MAAM,IAAI,MACR,CAAC,QAAQ,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,KAC/C,mBAAmB,IAAI,KAAK,GAAG,GACnC;CAGF,OAAO;AACT;AAEA,SAAgB,eACd,MACA,YAAgC,QAAQ,IAAI,MACxB;CACpB,KAAK,MAAM,aAAa,WAAW,MAAM,SAAS,KAAK,CAAC,GAAG;EACzD,IAAI,CAAC,WACH;EAEF,MAAM,YAAY,KAAK,WAAW,IAAI;EACtC,IAAI;GACF,WAAW,SAAS;GACpB,OAAO;EACT,QAAQ,CAAC;CACX;AAEF;AAEA,SAAS,qBACP,KAC+B;CAC/B,IAAI,CAAC,KACH;CAGF,MAAM,aAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,UAAU,KAAA,GACZ,WAAW,OAAO;CAGtB,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"stripPackagedWasm.js","names":[],"sources":["../../../src/build/stripPackagedWasm.ts"],"sourcesContent":["import { findExecutable, runCommand } from \"./runCommand.ts\";\n\nexport async function stripPackagedWasm(\n wasmPath: string\n): Promise<void> {\n const objcopyPath = findExecutable(\"llvm-objcopy\");\n if (!objcopyPath) {\n throw new Error(\n \"missing llvm-objcopy in PATH; install the swiftly-managed toolchain before packaging wasm\"\n );\n }\n\n await runCommand([\n objcopyPath,\n \"--strip-debug\",\n \"--remove-section=name\",\n wasmPath,\n ]);\n}\n"],"mappings":";;AAEA,eAAsB,kBACpB,UACe;CACf,MAAM,cAAc,eAAe,cAAc;CACjD,IAAI,CAAC,aACH,MAAM,IAAI,MACR,2FACF;CAGF,MAAM,WAAW;EACf;EACA;EACA;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"stripPackagedWasm.js","names":[],"sources":["../../../src/build/stripPackagedWasm.ts"],"sourcesContent":["import { findExecutable, runCommand } from \"./runCommand.ts\";\n\nexport async function stripPackagedWasm(wasmPath: string): Promise<void> {\n const objcopyPath = findExecutable(\"llvm-objcopy\");\n if (!objcopyPath) {\n throw new Error(\n \"missing llvm-objcopy in PATH; install the swiftly-managed toolchain before packaging wasm\",\n );\n }\n\n await runCommand([\n objcopyPath,\n \"--strip-debug\",\n \"--remove-section=name\",\n wasmPath,\n ]);\n}\n"],"mappings":";;AAEA,eAAsB,kBAAkB,UAAiC;CACvE,MAAM,cAAc,eAAe,cAAc;CACjD,IAAI,CAAC,aACH,MAAM,IAAI,MACR,2FACF;CAGF,MAAM,WAAW;EACf;EACA;EACA;EACA;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"wasmTypeDiagnostics.js","names":[],"sources":["../../../src/build/wasmTypeDiagnostics.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nconst wasmMagic = [0x00, 0x61, 0x73, 0x6d] as const;\nconst wasmVersion = [0x01, 0x00, 0x00, 0x00] as const;\nconst typeSectionID = 1;\nconst functionTypeTag = 0x60;\nconst browserMaxTypeParameterCount = 1000;\n\ninterface SectionHeader {\n id: number;\n size: number;\n startOffset: number;\n nextOffset: number;\n}\n\ninterface ReadUnsignedLEB128Result {\n nextOffset: number;\n value: number;\n}\n\ninterface WasmTypeSummary {\n maxTypeParameterCount?: number;\n maxTypeParameterTypeIndex?: number;\n note?: string;\n overBrowserLimitTypes: number[];\n topParameterCounts: Array<{\n parameterCount: number;\n typeIndex: number;\n }>;\n typeCount?: number;\n}\n\nexport function formatWasmTypeDiagnostics(\n bytes: Uint8Array\n): string {\n const summary = summarizeWasmTypes(bytes);\n const components = [\n `size=${bytes.byteLength} bytes`,\n `sha256=${createHash(\"sha256\").update(bytes).digest(\"hex\")}`,\n ];\n\n if (summary.typeCount !== undefined) {\n components.push(`typeCount=${summary.typeCount}`);\n }\n if (summary.maxTypeParameterCount !== undefined) {\n components.push(`maxTypeParameterCount=${summary.maxTypeParameterCount}`);\n }\n if (summary.maxTypeParameterTypeIndex !== undefined) {\n components.push(`maxTypeParameterTypeIndex=${summary.maxTypeParameterTypeIndex}`);\n }\n if (summary.overBrowserLimitTypes.length > 0) {\n components.push(`overBrowserLimitTypes=${summary.overBrowserLimitTypes.join(\",\")}`);\n }\n if (summary.topParameterCounts.length > 0) {\n components.push(\n `largestTypes=${summary.topParameterCounts.map(formatLargestTypeSummary).join(\";\")}`\n );\n }\n if (summary.note) {\n components.push(`note=${summary.note}`);\n }\n\n return `wasm diagnostics: ${components.join(\", \")}`;\n}\n\nfunction formatLargestTypeSummary(\n summary: { parameterCount: number; typeIndex: number }\n): string {\n return `${summary.typeIndex}:${summary.parameterCount}`;\n}\n\nfunction summarizeWasmTypes(\n bytes: Uint8Array\n): WasmTypeSummary {\n if (!hasExpectedPrefix(bytes, 0, wasmMagic)) {\n return {\n note: \"missing wasm magic header\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n if (!hasExpectedPrefix(bytes, wasmMagic.length, wasmVersion)) {\n return {\n note: \"missing wasm version header\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n let offset = 8;\n while (offset < bytes.length) {\n let sectionHeader: SectionHeader;\n try {\n sectionHeader = readSectionHeader(bytes, offset);\n } catch (error) {\n return {\n note: `failed to read section header at byte ${offset}: ${describeError(error)}`,\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n if (sectionHeader.id === typeSectionID) {\n return summarizeTypeSection(bytes, sectionHeader.startOffset, sectionHeader.nextOffset);\n }\n\n offset = sectionHeader.nextOffset;\n }\n\n return {\n note: \"module has no type section\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n}\n\nfunction summarizeTypeSection(\n bytes: Uint8Array,\n startOffset: number,\n endOffset: number\n): WasmTypeSummary {\n let offset = startOffset;\n let typeCount: number;\n\n try {\n const result = readUnsignedLEB128(bytes, offset);\n typeCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read type vector length: ${describeError(error)}`,\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n let maxTypeParameterCount = -1;\n let maxTypeParameterTypeIndex = -1;\n const overBrowserLimitTypes: number[] = [];\n const topParameterCounts: Array<{ parameterCount: number; typeIndex: number }> = [];\n\n for (let typeIndex = 0; typeIndex < typeCount; typeIndex += 1) {\n if (offset >= endOffset) {\n return {\n note: `type section ended early while reading type ${typeIndex}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n const typeTag = bytes[offset];\n offset += 1;\n if (typeTag !== functionTypeTag) {\n return {\n note: `unexpected type tag 0x${typeTag.toString(16)} at type ${typeIndex}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n let parameterCount: number;\n try {\n const result = readUnsignedLEB128(bytes, offset);\n parameterCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read parameter count for type ${typeIndex}: ${describeError(error)}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n if (parameterCount > maxTypeParameterCount) {\n maxTypeParameterCount = parameterCount;\n maxTypeParameterTypeIndex = typeIndex;\n }\n if (parameterCount > browserMaxTypeParameterCount) {\n overBrowserLimitTypes.push(typeIndex);\n }\n updateLargestTypeSummaries(topParameterCounts, typeIndex, parameterCount);\n\n offset += parameterCount;\n if (offset > endOffset) {\n return {\n note: `parameter vector for type ${typeIndex} overruns type section`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n let resultCount: number;\n try {\n const result = readUnsignedLEB128(bytes, offset);\n resultCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read result count for type ${typeIndex}: ${describeError(error)}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n offset += resultCount;\n if (offset > endOffset) {\n return {\n note: `result vector for type ${typeIndex} overruns type section`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n }\n\n return {\n maxTypeParameterCount: maxTypeParameterCount >= 0 ? maxTypeParameterCount : undefined,\n maxTypeParameterTypeIndex: maxTypeParameterTypeIndex >= 0 ? maxTypeParameterTypeIndex : undefined,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n}\n\nfunction updateLargestTypeSummaries(\n summaries: Array<{ parameterCount: number; typeIndex: number }>,\n typeIndex: number,\n parameterCount: number\n): void {\n summaries.push({ parameterCount, typeIndex });\n summaries.sort((left, right) => {\n if (right.parameterCount === left.parameterCount) {\n return left.typeIndex - right.typeIndex;\n }\n return right.parameterCount - left.parameterCount;\n });\n summaries.splice(5);\n}\n\nfunction readSectionHeader(\n bytes: Uint8Array,\n offset: number\n): SectionHeader {\n if (offset >= bytes.length) {\n throw new Error(\"unexpected end of file\");\n }\n\n const id = bytes[offset];\n const size = readUnsignedLEB128(bytes, offset + 1);\n const startOffset = size.nextOffset;\n const nextOffset = startOffset + size.value;\n if (nextOffset > bytes.length) {\n throw new Error(`section ${id} overruns file bounds`);\n }\n\n return {\n id,\n size: size.value,\n startOffset,\n nextOffset,\n };\n}\n\nfunction readUnsignedLEB128(\n bytes: Uint8Array,\n offset: number\n): ReadUnsignedLEB128Result {\n let shift = 0;\n let value = 0;\n let nextOffset = offset;\n\n while (nextOffset < bytes.length) {\n const byte = bytes[nextOffset];\n nextOffset += 1;\n value |= (byte & 0x7f) << shift;\n if ((byte & 0x80) === 0) {\n return {\n nextOffset,\n value,\n };\n }\n shift += 7;\n }\n\n throw new Error(\"unterminated LEB128 value\");\n}\n\nfunction hasExpectedPrefix(\n bytes: Uint8Array,\n startOffset: number,\n expected: readonly number[]\n): boolean {\n if (startOffset + expected.length > bytes.length) {\n return false;\n }\n\n for (let index = 0; index < expected.length; index += 1) {\n if (bytes[startOffset + index] !== expected[index]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"wasmTypeDiagnostics.js","names":[],"sources":["../../../src/build/wasmTypeDiagnostics.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nconst wasmMagic = [0x00, 0x61, 0x73, 0x6d] as const;\nconst wasmVersion = [0x01, 0x00, 0x00, 0x00] as const;\nconst typeSectionID = 1;\nconst functionTypeTag = 0x60;\nconst browserMaxTypeParameterCount = 1000;\n\ninterface SectionHeader {\n id: number;\n size: number;\n startOffset: number;\n nextOffset: number;\n}\n\ninterface ReadUnsignedLEB128Result {\n nextOffset: number;\n value: number;\n}\n\ninterface WasmTypeSummary {\n maxTypeParameterCount?: number;\n maxTypeParameterTypeIndex?: number;\n note?: string;\n overBrowserLimitTypes: number[];\n topParameterCounts: Array<{\n parameterCount: number;\n typeIndex: number;\n }>;\n typeCount?: number;\n}\n\nexport function formatWasmTypeDiagnostics(bytes: Uint8Array): string {\n const summary = summarizeWasmTypes(bytes);\n const components = [\n `size=${bytes.byteLength} bytes`,\n `sha256=${createHash(\"sha256\").update(bytes).digest(\"hex\")}`,\n ];\n\n if (summary.typeCount !== undefined) {\n components.push(`typeCount=${summary.typeCount}`);\n }\n if (summary.maxTypeParameterCount !== undefined) {\n components.push(`maxTypeParameterCount=${summary.maxTypeParameterCount}`);\n }\n if (summary.maxTypeParameterTypeIndex !== undefined) {\n components.push(\n `maxTypeParameterTypeIndex=${summary.maxTypeParameterTypeIndex}`,\n );\n }\n if (summary.overBrowserLimitTypes.length > 0) {\n components.push(\n `overBrowserLimitTypes=${summary.overBrowserLimitTypes.join(\",\")}`,\n );\n }\n if (summary.topParameterCounts.length > 0) {\n components.push(\n `largestTypes=${summary.topParameterCounts.map(formatLargestTypeSummary).join(\";\")}`,\n );\n }\n if (summary.note) {\n components.push(`note=${summary.note}`);\n }\n\n return `wasm diagnostics: ${components.join(\", \")}`;\n}\n\nfunction formatLargestTypeSummary(summary: {\n parameterCount: number;\n typeIndex: number;\n}): string {\n return `${summary.typeIndex}:${summary.parameterCount}`;\n}\n\nfunction summarizeWasmTypes(bytes: Uint8Array): WasmTypeSummary {\n if (!hasExpectedPrefix(bytes, 0, wasmMagic)) {\n return {\n note: \"missing wasm magic header\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n if (!hasExpectedPrefix(bytes, wasmMagic.length, wasmVersion)) {\n return {\n note: \"missing wasm version header\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n let offset = 8;\n while (offset < bytes.length) {\n let sectionHeader: SectionHeader;\n try {\n sectionHeader = readSectionHeader(bytes, offset);\n } catch (error) {\n return {\n note: `failed to read section header at byte ${offset}: ${describeError(error)}`,\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n if (sectionHeader.id === typeSectionID) {\n return summarizeTypeSection(\n bytes,\n sectionHeader.startOffset,\n sectionHeader.nextOffset,\n );\n }\n\n offset = sectionHeader.nextOffset;\n }\n\n return {\n note: \"module has no type section\",\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n}\n\nfunction summarizeTypeSection(\n bytes: Uint8Array,\n startOffset: number,\n endOffset: number,\n): WasmTypeSummary {\n let offset = startOffset;\n let typeCount: number;\n\n try {\n const result = readUnsignedLEB128(bytes, offset);\n typeCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read type vector length: ${describeError(error)}`,\n overBrowserLimitTypes: [],\n topParameterCounts: [],\n };\n }\n\n let maxTypeParameterCount = -1;\n let maxTypeParameterTypeIndex = -1;\n const overBrowserLimitTypes: number[] = [];\n const topParameterCounts: Array<{\n parameterCount: number;\n typeIndex: number;\n }> = [];\n\n for (let typeIndex = 0; typeIndex < typeCount; typeIndex += 1) {\n if (offset >= endOffset) {\n return {\n note: `type section ended early while reading type ${typeIndex}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n const typeTag = bytes[offset];\n offset += 1;\n if (typeTag !== functionTypeTag) {\n return {\n note: `unexpected type tag 0x${typeTag.toString(16)} at type ${typeIndex}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n let parameterCount: number;\n try {\n const result = readUnsignedLEB128(bytes, offset);\n parameterCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read parameter count for type ${typeIndex}: ${describeError(error)}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n if (parameterCount > maxTypeParameterCount) {\n maxTypeParameterCount = parameterCount;\n maxTypeParameterTypeIndex = typeIndex;\n }\n if (parameterCount > browserMaxTypeParameterCount) {\n overBrowserLimitTypes.push(typeIndex);\n }\n updateLargestTypeSummaries(topParameterCounts, typeIndex, parameterCount);\n\n offset += parameterCount;\n if (offset > endOffset) {\n return {\n note: `parameter vector for type ${typeIndex} overruns type section`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n let resultCount: number;\n try {\n const result = readUnsignedLEB128(bytes, offset);\n resultCount = result.value;\n offset = result.nextOffset;\n } catch (error) {\n return {\n note: `failed to read result count for type ${typeIndex}: ${describeError(error)}`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n\n offset += resultCount;\n if (offset > endOffset) {\n return {\n note: `result vector for type ${typeIndex} overruns type section`,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n }\n }\n\n return {\n maxTypeParameterCount:\n maxTypeParameterCount >= 0 ? maxTypeParameterCount : undefined,\n maxTypeParameterTypeIndex:\n maxTypeParameterTypeIndex >= 0 ? maxTypeParameterTypeIndex : undefined,\n overBrowserLimitTypes,\n topParameterCounts,\n typeCount,\n };\n}\n\nfunction updateLargestTypeSummaries(\n summaries: Array<{ parameterCount: number; typeIndex: number }>,\n typeIndex: number,\n parameterCount: number,\n): void {\n summaries.push({ parameterCount, typeIndex });\n summaries.sort((left, right) => {\n if (right.parameterCount === left.parameterCount) {\n return left.typeIndex - right.typeIndex;\n }\n return right.parameterCount - left.parameterCount;\n });\n summaries.splice(5);\n}\n\nfunction readSectionHeader(bytes: Uint8Array, offset: number): SectionHeader {\n if (offset >= bytes.length) {\n throw new Error(\"unexpected end of file\");\n }\n\n const id = bytes[offset];\n const size = readUnsignedLEB128(bytes, offset + 1);\n const startOffset = size.nextOffset;\n const nextOffset = startOffset + size.value;\n if (nextOffset > bytes.length) {\n throw new Error(`section ${id} overruns file bounds`);\n }\n\n return {\n id,\n size: size.value,\n startOffset,\n nextOffset,\n };\n}\n\nfunction readUnsignedLEB128(\n bytes: Uint8Array,\n offset: number,\n): ReadUnsignedLEB128Result {\n let shift = 0;\n let value = 0;\n let nextOffset = offset;\n\n while (nextOffset < bytes.length) {\n const byte = bytes[nextOffset];\n nextOffset += 1;\n value |= (byte & 0x7f) << shift;\n if ((byte & 0x80) === 0) {\n return {\n nextOffset,\n value,\n };\n }\n shift += 7;\n }\n\n throw new Error(\"unterminated LEB128 value\");\n}\n\nfunction hasExpectedPrefix(\n bytes: Uint8Array,\n startOffset: number,\n expected: readonly number[],\n): boolean {\n if (startOffset + expected.length > bytes.length) {\n return false;\n }\n\n for (let index = 0; index < expected.length; index += 1) {\n if (bytes[startOffset + index] !== expected[index]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swifttui/build",
3
- "version": "0.13.5",
3
+ "version": "0.15.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@swifttui/web": "0.13.5"
42
+ "@swifttui/web": "0.15.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/bun": "1.3.14"