@forgeax/engine-pack 0.1.2

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.
Files changed (228) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +370 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/ai-recovery.unit.test.d.ts +2 -0
  5. package/dist/__tests__/ai-recovery.unit.test.d.ts.map +1 -0
  6. package/dist/__tests__/artifact-path.test.d.ts +2 -0
  7. package/dist/__tests__/artifact-path.test.d.ts.map +1 -0
  8. package/dist/__tests__/asset-evidence-error-hints.test.d.ts +2 -0
  9. package/dist/__tests__/asset-evidence-error-hints.test.d.ts.map +1 -0
  10. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts +2 -0
  11. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts.map +1 -0
  12. package/dist/__tests__/asset-evidence-schema.test.d.ts +2 -0
  13. package/dist/__tests__/asset-evidence-schema.test.d.ts.map +1 -0
  14. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts +2 -0
  15. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts.map +1 -0
  16. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts +2 -0
  17. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts +2 -0
  19. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts.map +1 -0
  20. package/dist/__tests__/cli.unit.test.d.ts +2 -0
  21. package/dist/__tests__/cli.unit.test.d.ts.map +1 -0
  22. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts +2 -0
  23. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/guid-collision.unit.test.d.ts +2 -0
  25. package/dist/__tests__/guid-collision.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/guid-validator-surface.unit.test.d.ts +2 -0
  27. package/dist/__tests__/guid-validator-surface.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/load-asset-config.test.d.ts +2 -0
  29. package/dist/__tests__/load-asset-config.test.d.ts.map +1 -0
  30. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts +2 -0
  31. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/material-cook-receipt.unit.test.d.ts +2 -0
  33. package/dist/__tests__/material-cook-receipt.unit.test.d.ts.map +1 -0
  34. package/dist/__tests__/material-cook-schema.unit.test.d.ts +2 -0
  35. package/dist/__tests__/material-cook-schema.unit.test.d.ts.map +1 -0
  36. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts +2 -0
  37. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts +2 -0
  39. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/meta-schema-optional.test.d.ts +2 -0
  41. package/dist/__tests__/meta-schema-optional.test.d.ts.map +1 -0
  42. package/dist/__tests__/meta-source-overrides.unit.test.d.ts +2 -0
  43. package/dist/__tests__/meta-source-overrides.unit.test.d.ts.map +1 -0
  44. package/dist/__tests__/native-cooker-registry.test.d.ts +2 -0
  45. package/dist/__tests__/native-cooker-registry.test.d.ts.map +1 -0
  46. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts +2 -0
  47. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts.map +1 -0
  48. package/dist/__tests__/offline-evidence.integration.test.d.ts +2 -0
  49. package/dist/__tests__/offline-evidence.integration.test.d.ts.map +1 -0
  50. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts +2 -0
  51. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts.map +1 -0
  52. package/dist/__tests__/pack-v2-schema.test.d.ts +2 -0
  53. package/dist/__tests__/pack-v2-schema.test.d.ts.map +1 -0
  54. package/dist/__tests__/pack.unit.test.d.ts +2 -0
  55. package/dist/__tests__/pack.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/producer-contract-schema.unit.test.d.ts +2 -0
  57. package/dist/__tests__/producer-contract-schema.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/resolve-asset-source.test.d.ts +2 -0
  59. package/dist/__tests__/resolve-asset-source.test.d.ts.map +1 -0
  60. package/dist/__tests__/runtime-projection.unit.test.d.ts +2 -0
  61. package/dist/__tests__/runtime-projection.unit.test.d.ts.map +1 -0
  62. package/dist/__tests__/scanner-inventory.test.d.ts +2 -0
  63. package/dist/__tests__/scanner-inventory.test.d.ts.map +1 -0
  64. package/dist/__tests__/scanner-mount-cycle.test.d.ts +2 -0
  65. package/dist/__tests__/scanner-mount-cycle.test.d.ts.map +1 -0
  66. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts +2 -0
  67. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts.map +1 -0
  68. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts +2 -0
  69. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts.map +1 -0
  70. package/dist/__tests__/scriptable-pack.test-d.d.ts +2 -0
  71. package/dist/__tests__/scriptable-pack.test-d.d.ts.map +1 -0
  72. package/dist/__tests__/scriptable-pack.unit.test.d.ts +2 -0
  73. package/dist/__tests__/scriptable-pack.unit.test.d.ts.map +1 -0
  74. package/dist/__tests__/topology-actions.unit.test.d.ts +2 -0
  75. package/dist/__tests__/topology-actions.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/topology.unit.test.d.ts +2 -0
  77. package/dist/__tests__/topology.unit.test.d.ts.map +1 -0
  78. package/dist/artifact-path.d.ts +9 -0
  79. package/dist/artifact-path.d.ts.map +1 -0
  80. package/dist/atlas/run-atlas.d.ts +8 -0
  81. package/dist/atlas/run-atlas.d.ts.map +1 -0
  82. package/dist/atlas/shelf-pack.d.ts +55 -0
  83. package/dist/atlas/shelf-pack.d.ts.map +1 -0
  84. package/dist/bridge.d.ts +2 -0
  85. package/dist/bridge.d.ts.map +1 -0
  86. package/dist/bridge.mjs +3 -0
  87. package/dist/bridge.mjs.map +1 -0
  88. package/dist/builtin.d.ts +24 -0
  89. package/dist/builtin.d.ts.map +1 -0
  90. package/dist/cli-asset.d.ts +22 -0
  91. package/dist/cli-asset.d.ts.map +1 -0
  92. package/dist/cli-asset.mjs +9950 -0
  93. package/dist/cli-asset.mjs.map +1 -0
  94. package/dist/config.d.ts +6 -0
  95. package/dist/config.d.ts.map +1 -0
  96. package/dist/config.mjs +29 -0
  97. package/dist/config.mjs.map +1 -0
  98. package/dist/deriveAssetName.d.ts +15 -0
  99. package/dist/deriveAssetName.d.ts.map +1 -0
  100. package/dist/errors.d.ts +30 -0
  101. package/dist/errors.d.ts.map +1 -0
  102. package/dist/errors.mjs +19 -0
  103. package/dist/errors.mjs.map +1 -0
  104. package/dist/evidence/material-cook.d.ts +70 -0
  105. package/dist/evidence/material-cook.d.ts.map +1 -0
  106. package/dist/evidence/offline-evidence.d.ts +25 -0
  107. package/dist/evidence/offline-evidence.d.ts.map +1 -0
  108. package/dist/evidence/source-inventory.d.ts +29 -0
  109. package/dist/evidence/source-inventory.d.ts.map +1 -0
  110. package/dist/guid.d.ts +45 -0
  111. package/dist/guid.d.ts.map +1 -0
  112. package/dist/guid.mjs +94 -0
  113. package/dist/guid.mjs.map +1 -0
  114. package/dist/index.d.ts +15 -0
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.mjs +8475 -0
  117. package/dist/index.mjs.map +1 -0
  118. package/dist/material/artifact-writer.d.ts +14 -0
  119. package/dist/material/artifact-writer.d.ts.map +1 -0
  120. package/dist/mesh-bin-contract.d.ts +36 -0
  121. package/dist/mesh-bin-contract.d.ts.map +1 -0
  122. package/dist/name.mjs +22 -0
  123. package/dist/name.mjs.map +1 -0
  124. package/dist/native-cooker-registry.d.ts +28 -0
  125. package/dist/native-cooker-registry.d.ts.map +1 -0
  126. package/dist/native-cooker.d.ts +3 -0
  127. package/dist/native-cooker.d.ts.map +1 -0
  128. package/dist/native-cooker.mjs +105 -0
  129. package/dist/native-cooker.mjs.map +1 -0
  130. package/dist/producer-contract.d.ts +19 -0
  131. package/dist/producer-contract.d.ts.map +1 -0
  132. package/dist/resolve-asset-source.d.ts +4 -0
  133. package/dist/resolve-asset-source.d.ts.map +1 -0
  134. package/dist/resolve-asset-source.mjs +99 -0
  135. package/dist/resolve-asset-source.mjs.map +1 -0
  136. package/dist/runtime-projection.d.ts +14 -0
  137. package/dist/runtime-projection.d.ts.map +1 -0
  138. package/dist/scanner.d.ts +80 -0
  139. package/dist/scanner.d.ts.map +1 -0
  140. package/dist/scanner.mjs +9015 -0
  141. package/dist/scanner.mjs.map +1 -0
  142. package/dist/schema-compiled.d.ts +12 -0
  143. package/dist/schema-compiled.d.ts.map +1 -0
  144. package/dist/schema.mjs +7369 -0
  145. package/dist/schema.mjs.map +1 -0
  146. package/dist/scriptable-pack-node.d.ts +67 -0
  147. package/dist/scriptable-pack-node.d.ts.map +1 -0
  148. package/dist/scriptable-pack-node.mjs +1590 -0
  149. package/dist/scriptable-pack-node.mjs.map +1 -0
  150. package/dist/scriptable-pack-worker.d.ts +2 -0
  151. package/dist/scriptable-pack-worker.d.ts.map +1 -0
  152. package/dist/scriptable-pack-worker.mjs +223 -0
  153. package/dist/scriptable-pack-worker.mjs.map +1 -0
  154. package/dist/scriptable-pack.d.ts +525 -0
  155. package/dist/scriptable-pack.d.ts.map +1 -0
  156. package/dist/scriptable-pack.mjs +583 -0
  157. package/dist/scriptable-pack.mjs.map +1 -0
  158. package/dist/topology.d.ts +10 -0
  159. package/dist/topology.d.ts.map +1 -0
  160. package/package.json +129 -0
  161. package/schema/meta.schema.json +173 -0
  162. package/schema/pack.schema.json +232 -0
  163. package/src/__tests__/ai-recovery.unit.test.ts +114 -0
  164. package/src/__tests__/artifact-path.test.ts +41 -0
  165. package/src/__tests__/asset-evidence-error-hints.test.ts +46 -0
  166. package/src/__tests__/asset-evidence-lifecycle.test.ts +104 -0
  167. package/src/__tests__/asset-evidence-schema.test.ts +86 -0
  168. package/src/__tests__/atlas-cli-region-mismatch.test.ts +134 -0
  169. package/src/__tests__/atlas-error-code-owner.test-d.ts +23 -0
  170. package/src/__tests__/cli-asset-evidence.integration.test.ts +172 -0
  171. package/src/__tests__/cli.unit.test.ts +448 -0
  172. package/src/__tests__/evidence-source-inventory.unit.test.ts +37 -0
  173. package/src/__tests__/guid-collision.unit.test.ts +112 -0
  174. package/src/__tests__/guid-validator-surface.unit.test.ts +20 -0
  175. package/src/__tests__/load-asset-config.test.ts +121 -0
  176. package/src/__tests__/material-cook-dependencies.unit.test.ts +45 -0
  177. package/src/__tests__/material-cook-receipt.unit.test.ts +91 -0
  178. package/src/__tests__/material-cook-schema.unit.test.ts +98 -0
  179. package/src/__tests__/mesh-bin-consumer-surface.unit.test.ts +21 -0
  180. package/src/__tests__/mesh-bin-contract.unit.test.ts +32 -0
  181. package/src/__tests__/meta-schema-optional.test.ts +116 -0
  182. package/src/__tests__/meta-source-overrides.unit.test.ts +71 -0
  183. package/src/__tests__/native-cooker-registry.test.ts +64 -0
  184. package/src/__tests__/offline-evidence-artifact-verification-owner.test-d.ts +64 -0
  185. package/src/__tests__/offline-evidence.integration.test.ts +106 -0
  186. package/src/__tests__/pack-v2-fixture-migration.test.ts +64 -0
  187. package/src/__tests__/pack-v2-schema.test.ts +142 -0
  188. package/src/__tests__/pack.unit.test.ts +2218 -0
  189. package/src/__tests__/producer-contract-schema.unit.test.ts +92 -0
  190. package/src/__tests__/resolve-asset-source.test.ts +121 -0
  191. package/src/__tests__/runtime-projection.unit.test.ts +87 -0
  192. package/src/__tests__/scanner-inventory.test.ts +72 -0
  193. package/src/__tests__/scanner-mount-cycle.test.ts +232 -0
  194. package/src/__tests__/scriptable-pack-cli.integration.test.ts +47 -0
  195. package/src/__tests__/scriptable-pack-ddc-key.unit.test.ts +63 -0
  196. package/src/__tests__/scriptable-pack.test-d.ts +131 -0
  197. package/src/__tests__/scriptable-pack.unit.test.ts +747 -0
  198. package/src/__tests__/topology-actions.unit.test.ts +94 -0
  199. package/src/__tests__/topology.unit.test.ts +85 -0
  200. package/src/artifact-path.ts +69 -0
  201. package/src/atlas/run-atlas.ts +358 -0
  202. package/src/atlas/shelf-pack.ts +176 -0
  203. package/src/atlas/upng-ambient.d.ts +13 -0
  204. package/src/bridge.ts +2 -0
  205. package/src/builtin.ts +79 -0
  206. package/src/cli-asset.ts +590 -0
  207. package/src/config.ts +36 -0
  208. package/src/deriveAssetName.ts +42 -0
  209. package/src/errors.ts +47 -0
  210. package/src/evidence/material-cook.ts +332 -0
  211. package/src/evidence/offline-evidence.ts +90 -0
  212. package/src/evidence/source-inventory.ts +193 -0
  213. package/src/guid.ts +99 -0
  214. package/src/index.ts +104 -0
  215. package/src/material/artifact-writer.ts +26 -0
  216. package/src/mesh-bin-contract.ts +150 -0
  217. package/src/native-cooker-registry.ts +163 -0
  218. package/src/native-cooker.ts +2 -0
  219. package/src/producer-contract.ts +277 -0
  220. package/src/resolve-asset-source.ts +93 -0
  221. package/src/runtime-projection.ts +100 -0
  222. package/src/scanner.ts +716 -0
  223. package/src/schema/material-cook.schema.json +79 -0
  224. package/src/schema-compiled.ts +238 -0
  225. package/src/scriptable-pack-node.ts +1390 -0
  226. package/src/scriptable-pack-worker.ts +306 -0
  227. package/src/scriptable-pack.ts +884 -0
  228. package/src/topology.ts +156 -0
@@ -0,0 +1,306 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { dirname, extname, join, resolve } from 'node:path';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
+ import { parentPort, workerData } from 'node:worker_threads';
6
+ import ts from 'typescript';
7
+
8
+ if (parentPort === null) throw new Error('ScriptablePack worker requires a parent port');
9
+
10
+ const port = parentPort;
11
+ const workerMode = workerData as {
12
+ readonly mode?: 'single' | 'reusable';
13
+ readonly sourcePath?: string;
14
+ readonly compileRoot?: string;
15
+ };
16
+ const reusable = workerMode.mode === 'reusable';
17
+ let sourcePath = workerMode.sourcePath;
18
+ let compileRoot = workerMode.compileRoot;
19
+ type LoadedDefinition = {
20
+ readonly schemaVersion?: unknown;
21
+ readonly packageId?: unknown;
22
+ readonly name?: unknown;
23
+ readonly assets?: unknown;
24
+ readonly externalAssets?: unknown;
25
+ readonly build?: unknown;
26
+ };
27
+ let definition: LoadedDefinition | undefined;
28
+ let nextReadId = 0;
29
+ const reads = new Map<number, (value: unknown) => void>();
30
+
31
+ function failure(error: unknown): unknown {
32
+ if (error === null || typeof error !== 'object') return error;
33
+ const value = error as Record<string, unknown>;
34
+ return {
35
+ name: value.name,
36
+ code: value.code,
37
+ expected: value.expected,
38
+ actual: value.actual,
39
+ hint: value.hint,
40
+ detail: value.detail,
41
+ message: value.message,
42
+ };
43
+ }
44
+
45
+ const SOURCE_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs'] as const;
46
+
47
+ function resolveRelativeImport(importer: string, specifier: string): string | undefined {
48
+ if (!specifier.startsWith('.')) return undefined;
49
+ const raw = resolve(dirname(importer), specifier);
50
+ const candidates =
51
+ extname(raw).length > 0
52
+ ? [raw]
53
+ : [
54
+ raw,
55
+ ...SOURCE_EXTENSIONS.map((extension) => `${raw}${extension}`),
56
+ resolve(raw, 'index.ts'),
57
+ ];
58
+ return candidates.find((candidate) => existsSync(candidate));
59
+ }
60
+
61
+ function outputName(path: string): string {
62
+ const digest = createHash('sha256').update(path).digest('hex').slice(0, 20);
63
+ return `${digest}.mjs`;
64
+ }
65
+
66
+ function resolveBareImport(importer: string, specifier: string): string | undefined {
67
+ const resolver = (
68
+ import.meta as ImportMeta & {
69
+ readonly resolve?: (specifier: string, parent?: string) => string;
70
+ }
71
+ ).resolve;
72
+ if (resolver === undefined) return undefined;
73
+ try {
74
+ const resolved = resolver(specifier, pathToFileURL(importer).href);
75
+ return resolved.startsWith('file:') ? fileURLToPath(resolved) : undefined;
76
+ } catch {
77
+ // Type-only or optional imports may not be installed in the game project.
78
+ // Preserve them for TypeScript to erase or let Node report the real load
79
+ // failure instead of guessing a workspace root.
80
+ return undefined;
81
+ }
82
+ }
83
+
84
+ function resolvedModuleSpecifier(
85
+ target: string,
86
+ sources: ReadonlyMap<string, string>,
87
+ loadId?: number,
88
+ ): string {
89
+ if (sources.has(target)) {
90
+ return `./${outputName(target)}${loadId === undefined ? '' : `?load=${loadId}`}`;
91
+ }
92
+ return pathToFileURL(target).href;
93
+ }
94
+
95
+ /**
96
+ * Node 22 does not execute `.ts` modules. Compile the trusted local module
97
+ * closure into one disposable ESM directory before importing it. Bare package
98
+ * imports are resolved by Node from the original source module and rewritten
99
+ * to their canonical file URL; relative imports are rewritten to the compiled
100
+ * closure by identity. This keeps unrelated nested node_modules directories
101
+ * (for example Vite's cache) from changing package resolution.
102
+ */
103
+ function compileModuleClosure(entryPath: string, outputRoot: string, loadId?: number): string {
104
+ const pending = [resolve(entryPath)];
105
+ const sources = new Map<string, string>();
106
+ const imports = new Map<string, ReadonlyMap<string, string>>();
107
+ while (pending.length > 0) {
108
+ const path = pending.pop();
109
+ if (path === undefined || sources.has(path)) continue;
110
+ const source = readFileSync(path, 'utf8');
111
+ sources.set(path, source);
112
+ const resolvedImports = new Map<string, string>();
113
+ for (const imported of ts.preProcessFile(source, true, true).importedFiles) {
114
+ const target = imported.fileName.startsWith('.')
115
+ ? resolveRelativeImport(path, imported.fileName)
116
+ : resolveBareImport(path, imported.fileName);
117
+ if (target === undefined) continue;
118
+ resolvedImports.set(imported.fileName, target);
119
+ if (imported.fileName.startsWith('.') || /\.(?:ts|tsx|mts|cts)$/.test(target)) {
120
+ pending.push(target);
121
+ }
122
+ }
123
+ imports.set(path, resolvedImports);
124
+ }
125
+
126
+ for (const [path, source] of sources) {
127
+ const replacements = imports.get(path) ?? new Map<string, string>();
128
+ const rewriteRelativeImports: ts.TransformerFactory<ts.SourceFile> = (context) => {
129
+ const visit: ts.Visitor = (node) => {
130
+ if (
131
+ (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
132
+ node.moduleSpecifier !== undefined &&
133
+ ts.isStringLiteral(node.moduleSpecifier)
134
+ ) {
135
+ const target = replacements.get(node.moduleSpecifier.text);
136
+ if (target !== undefined) {
137
+ const moduleSpecifier = ts.factory.createStringLiteral(
138
+ resolvedModuleSpecifier(target, sources, loadId),
139
+ );
140
+ return ts.isImportDeclaration(node)
141
+ ? ts.factory.updateImportDeclaration(
142
+ node,
143
+ node.modifiers,
144
+ node.importClause,
145
+ moduleSpecifier,
146
+ node.attributes,
147
+ )
148
+ : ts.factory.updateExportDeclaration(
149
+ node,
150
+ node.modifiers,
151
+ node.isTypeOnly,
152
+ node.exportClause,
153
+ moduleSpecifier,
154
+ node.attributes,
155
+ );
156
+ }
157
+ }
158
+ if (
159
+ ts.isCallExpression(node) &&
160
+ node.expression.kind === ts.SyntaxKind.ImportKeyword &&
161
+ node.arguments.length === 1 &&
162
+ node.arguments[0] !== undefined &&
163
+ ts.isStringLiteral(node.arguments[0])
164
+ ) {
165
+ const target = replacements.get(node.arguments[0].text);
166
+ if (target !== undefined) {
167
+ return ts.factory.updateCallExpression(node, node.expression, node.typeArguments, [
168
+ ts.factory.createStringLiteral(resolvedModuleSpecifier(target, sources, loadId)),
169
+ ]);
170
+ }
171
+ }
172
+ return ts.visitEachChild(node, visit, context);
173
+ };
174
+ return (sourceFile) => ts.visitNode(sourceFile, visit) as ts.SourceFile;
175
+ };
176
+ const transpiled = ts.transpileModule(source, {
177
+ fileName: path,
178
+ compilerOptions: {
179
+ target: ts.ScriptTarget.ES2022,
180
+ module: ts.ModuleKind.ESNext,
181
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
182
+ isolatedModules: true,
183
+ sourceMap: false,
184
+ },
185
+ transformers: { before: [rewriteRelativeImports] },
186
+ reportDiagnostics: true,
187
+ });
188
+ const errors =
189
+ transpiled.diagnostics?.filter(
190
+ (diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error,
191
+ ) ?? [];
192
+ if (errors.length > 0) {
193
+ throw new Error(
194
+ `ScriptablePack TypeScript transpile failed for ${path}: ${errors
195
+ .map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'))
196
+ .join('; ')}`,
197
+ );
198
+ }
199
+ writeFileSync(join(outputRoot, outputName(path)), transpiled.outputText);
200
+ }
201
+ return join(outputRoot, outputName(resolve(entryPath)));
202
+ }
203
+
204
+ async function loadDefinition(task: {
205
+ readonly sourcePath: string;
206
+ readonly compileRoot: string;
207
+ readonly loadId?: number;
208
+ }): Promise<void> {
209
+ sourcePath = task.sourcePath;
210
+ compileRoot = task.compileRoot;
211
+ definition = undefined;
212
+ reads.clear();
213
+ const executablePath = SOURCE_EXTENSIONS.includes(
214
+ extname(task.sourcePath) as (typeof SOURCE_EXTENSIONS)[number],
215
+ )
216
+ ? compileModuleClosure(task.sourcePath, task.compileRoot, task.loadId)
217
+ : task.sourcePath;
218
+ const loaded = (await import(
219
+ `${pathToFileURL(executablePath).href}${reusable ? `?load=${task.loadId ?? 0}` : ''}`
220
+ )) as {
221
+ readonly default?: unknown;
222
+ };
223
+ definition = loaded.default as LoadedDefinition | undefined;
224
+ port.postMessage({
225
+ kind: 'loaded',
226
+ ...(task.loadId === undefined ? {} : { loadId: task.loadId }),
227
+ definition:
228
+ definition === undefined
229
+ ? undefined
230
+ : {
231
+ schemaVersion: definition.schemaVersion,
232
+ packageId: definition.packageId,
233
+ name: definition.name,
234
+ assets: definition.assets,
235
+ externalAssets: definition.externalAssets,
236
+ },
237
+ });
238
+ }
239
+
240
+ async function handleMessage(message: unknown): Promise<void> {
241
+ if (message === null || typeof message !== 'object') return;
242
+ const value = message as Record<string, unknown>;
243
+ if (value.kind === 'asset-result' && typeof value.readId === 'number') {
244
+ reads.get(value.readId)?.(value.result);
245
+ reads.delete(value.readId);
246
+ return;
247
+ }
248
+ if (
249
+ reusable &&
250
+ value.kind === 'load' &&
251
+ typeof value.sourcePath === 'string' &&
252
+ typeof value.compileRoot === 'string' &&
253
+ typeof value.loadId === 'number'
254
+ ) {
255
+ try {
256
+ await loadDefinition({
257
+ sourcePath: value.sourcePath,
258
+ compileRoot: value.compileRoot,
259
+ loadId: value.loadId,
260
+ });
261
+ } catch (error) {
262
+ port.postMessage({ kind: 'load-threw', loadId: value.loadId, error: failure(error) });
263
+ }
264
+ return;
265
+ }
266
+ if (value.kind !== 'build' || typeof value.buildId !== 'number') return;
267
+ if (typeof definition?.build !== 'function') {
268
+ port.postMessage({
269
+ kind: 'build-result',
270
+ buildId: value.buildId,
271
+ result: { ok: false, error: { message: 'default export has no build function' } },
272
+ });
273
+ return;
274
+ }
275
+ try {
276
+ const result = await definition.build({
277
+ readByGuid(guid: Uint8Array): Promise<unknown> {
278
+ const readId = nextReadId++;
279
+ port.postMessage({ kind: 'asset-read', buildId: value.buildId, readId, guid });
280
+ return new Promise((resolve) => reads.set(readId, resolve));
281
+ },
282
+ });
283
+ port.postMessage({
284
+ kind: 'build-result',
285
+ buildId: value.buildId,
286
+ result:
287
+ result !== null && typeof result === 'object' && 'ok' in result && !result.ok
288
+ ? { ...result, error: failure(result.error) }
289
+ : result,
290
+ });
291
+ } catch (error) {
292
+ port.postMessage({ kind: 'build-threw', buildId: value.buildId, error: failure(error) });
293
+ }
294
+ }
295
+
296
+ port.on('message', (message: unknown) => {
297
+ void handleMessage(message);
298
+ });
299
+
300
+ if (!reusable && sourcePath !== undefined && compileRoot !== undefined) {
301
+ try {
302
+ await loadDefinition({ sourcePath, compileRoot });
303
+ } catch (error) {
304
+ port.postMessage({ kind: 'load-threw', error: failure(error) });
305
+ }
306
+ }