@forgeax/engine-pack 0.1.23 → 0.1.25

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 (157) hide show
  1. package/README.md +12 -6
  2. package/dist/build.d.ts +4 -4
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/build.mjs +390 -294
  5. package/dist/build.mjs.map +1 -1
  6. package/dist/cli-asset.mjs +33 -35
  7. package/dist/cli-asset.mjs.map +1 -1
  8. package/dist/evidence/material-cook.d.ts +26 -0
  9. package/dist/evidence/material-cook.d.ts.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.mjs +121 -27
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/material-cook.d.ts +1 -1
  15. package/dist/material-cook.d.ts.map +1 -1
  16. package/dist/material-cook.mjs +102 -4
  17. package/dist/material-cook.mjs.map +1 -1
  18. package/dist/{parameterized-pack-node.d.ts → pack-authoring-node.d.ts} +7 -7
  19. package/dist/pack-authoring-node.d.ts.map +1 -0
  20. package/dist/{parameterized-pack-node.mjs → pack-authoring-node.mjs} +59 -63
  21. package/dist/pack-authoring-node.mjs.map +1 -0
  22. package/dist/{parameterized-pack.d.ts → pack-authoring.d.ts} +28 -31
  23. package/dist/pack-authoring.d.ts.map +1 -0
  24. package/dist/pack-authoring.mjs +1137 -0
  25. package/dist/pack-authoring.mjs.map +1 -0
  26. package/dist/runtime.mjs +1 -1
  27. package/dist/runtime.mjs.map +1 -1
  28. package/dist/scanner.d.ts +11 -9
  29. package/dist/scanner.d.ts.map +1 -1
  30. package/dist/scanner.mjs +36 -34
  31. package/dist/scanner.mjs.map +1 -1
  32. package/dist/schema.mjs +1 -1
  33. package/dist/schema.mjs.map +1 -1
  34. package/dist/scriptable-pack-node.d.ts +4 -4
  35. package/dist/scriptable-pack-node.d.ts.map +1 -1
  36. package/dist/scriptable-pack-node.mjs +18 -20
  37. package/dist/scriptable-pack-node.mjs.map +1 -1
  38. package/dist/scriptable-pack.d.ts +3 -2
  39. package/dist/scriptable-pack.d.ts.map +1 -1
  40. package/dist/scriptable-pack.mjs +19 -23
  41. package/dist/scriptable-pack.mjs.map +1 -1
  42. package/package.json +2 -7
  43. package/schema/pack.schema.json +1 -1
  44. package/src/__tests__/material-cook-receipt-layer-plan.unit.test.ts +16 -0
  45. package/src/__tests__/material-cook-schema.unit.test.ts +62 -0
  46. package/src/__tests__/material-declaration-boundary.unit.test.ts +35 -0
  47. package/src/__tests__/material-surface-consumer-census.test.ts +24 -0
  48. package/src/__tests__/material-surface-publication.unit.test.ts +159 -0
  49. package/src/__tests__/material-surface-wire.unit.test.ts +30 -0
  50. package/src/__tests__/{parameterized-pack-authoring-gateway.unit.test.ts → pack-authoring-gateway.unit.test.ts} +9 -9
  51. package/src/__tests__/{parameterized-pack.unit.test.ts → pack-authoring.unit.test.ts} +10 -10
  52. package/src/__tests__/{parameterized-pack-scanner.unit.test.ts → pack-scanner.unit.test.ts} +6 -6
  53. package/src/__tests__/scanner-inventory.contract.test.ts +2 -4
  54. package/src/__tests__/scanner-inventory.test.ts +7 -6
  55. package/src/__tests__/scriptable-pack-cli.integration.test.ts +1 -1
  56. package/src/build.ts +10 -8
  57. package/src/catalog-builder.ts +3 -3
  58. package/src/cli-asset.ts +5 -5
  59. package/src/evidence/material-cook.ts +170 -7
  60. package/src/evidence/source-inventory.ts +3 -3
  61. package/src/index.ts +6 -1
  62. package/src/material-cook.ts +3 -0
  63. package/src/{parameterized-pack-node.ts → pack-authoring-node.ts} +71 -73
  64. package/src/{parameterized-pack.ts → pack-authoring.ts} +59 -74
  65. package/src/scanner.ts +33 -31
  66. package/src/schema/material-cook.schema.json +47 -1
  67. package/src/scriptable-pack-node.ts +25 -25
  68. package/src/scriptable-pack.ts +3 -2
  69. package/dist/__tests__/ai-recovery.unit.test.d.ts +0 -2
  70. package/dist/__tests__/ai-recovery.unit.test.d.ts.map +0 -1
  71. package/dist/__tests__/artifact-path.test.d.ts +0 -2
  72. package/dist/__tests__/artifact-path.test.d.ts.map +0 -1
  73. package/dist/__tests__/asset-evidence-error-hints.test.d.ts +0 -2
  74. package/dist/__tests__/asset-evidence-error-hints.test.d.ts.map +0 -1
  75. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts +0 -2
  76. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts.map +0 -1
  77. package/dist/__tests__/asset-evidence-schema.test.d.ts +0 -2
  78. package/dist/__tests__/asset-evidence-schema.test.d.ts.map +0 -1
  79. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts +0 -2
  80. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts.map +0 -1
  81. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts +0 -2
  82. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts.map +0 -1
  83. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts +0 -2
  84. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts.map +0 -1
  85. package/dist/__tests__/cli.unit.test.d.ts +0 -2
  86. package/dist/__tests__/cli.unit.test.d.ts.map +0 -1
  87. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts +0 -2
  88. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts.map +0 -1
  89. package/dist/__tests__/guid-collision.unit.test.d.ts +0 -2
  90. package/dist/__tests__/guid-collision.unit.test.d.ts.map +0 -1
  91. package/dist/__tests__/guid-validator-surface.unit.test.d.ts +0 -2
  92. package/dist/__tests__/guid-validator-surface.unit.test.d.ts.map +0 -1
  93. package/dist/__tests__/inventory-schema.test.d.ts +0 -2
  94. package/dist/__tests__/inventory-schema.test.d.ts.map +0 -1
  95. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts +0 -2
  96. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts.map +0 -1
  97. package/dist/__tests__/material-cook-receipt.unit.test.d.ts +0 -2
  98. package/dist/__tests__/material-cook-receipt.unit.test.d.ts.map +0 -1
  99. package/dist/__tests__/material-cook-schema.unit.test.d.ts +0 -2
  100. package/dist/__tests__/material-cook-schema.unit.test.d.ts.map +0 -1
  101. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts +0 -2
  102. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts.map +0 -1
  103. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts +0 -2
  104. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts.map +0 -1
  105. package/dist/__tests__/meta-schema-optional.test.d.ts +0 -2
  106. package/dist/__tests__/meta-schema-optional.test.d.ts.map +0 -1
  107. package/dist/__tests__/meta-source-overrides.unit.test.d.ts +0 -2
  108. package/dist/__tests__/meta-source-overrides.unit.test.d.ts.map +0 -1
  109. package/dist/__tests__/native-cooker-registry.test.d.ts +0 -2
  110. package/dist/__tests__/native-cooker-registry.test.d.ts.map +0 -1
  111. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts +0 -2
  112. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts.map +0 -1
  113. package/dist/__tests__/offline-evidence.integration.test.d.ts +0 -2
  114. package/dist/__tests__/offline-evidence.integration.test.d.ts.map +0 -1
  115. package/dist/__tests__/owner-chain.integration.test.d.ts +0 -2
  116. package/dist/__tests__/owner-chain.integration.test.d.ts.map +0 -1
  117. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts +0 -2
  118. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts.map +0 -1
  119. package/dist/__tests__/pack-v2-schema.test.d.ts +0 -2
  120. package/dist/__tests__/pack-v2-schema.test.d.ts.map +0 -1
  121. package/dist/__tests__/pack.unit.test.d.ts +0 -2
  122. package/dist/__tests__/pack.unit.test.d.ts.map +0 -1
  123. package/dist/__tests__/package-finalizer.contract.test.d.ts +0 -2
  124. package/dist/__tests__/package-finalizer.contract.test.d.ts.map +0 -1
  125. package/dist/__tests__/parameterized-pack-authoring-gateway.unit.test.d.ts +0 -2
  126. package/dist/__tests__/parameterized-pack-authoring-gateway.unit.test.d.ts.map +0 -1
  127. package/dist/__tests__/parameterized-pack-scanner.unit.test.d.ts +0 -2
  128. package/dist/__tests__/parameterized-pack-scanner.unit.test.d.ts.map +0 -1
  129. package/dist/__tests__/parameterized-pack.unit.test.d.ts +0 -2
  130. package/dist/__tests__/parameterized-pack.unit.test.d.ts.map +0 -1
  131. package/dist/__tests__/producer-contract-schema.unit.test.d.ts +0 -2
  132. package/dist/__tests__/producer-contract-schema.unit.test.d.ts.map +0 -1
  133. package/dist/__tests__/resolve-asset-source.test.d.ts +0 -2
  134. package/dist/__tests__/resolve-asset-source.test.d.ts.map +0 -1
  135. package/dist/__tests__/runtime-projection.unit.test.d.ts +0 -2
  136. package/dist/__tests__/runtime-projection.unit.test.d.ts.map +0 -1
  137. package/dist/__tests__/runtime.browser.test.d.ts +0 -2
  138. package/dist/__tests__/runtime.browser.test.d.ts.map +0 -1
  139. package/dist/__tests__/scanner-blacklist.test.d.ts +0 -2
  140. package/dist/__tests__/scanner-blacklist.test.d.ts.map +0 -1
  141. package/dist/__tests__/scanner-inventory.contract.test.d.ts +0 -2
  142. package/dist/__tests__/scanner-inventory.contract.test.d.ts.map +0 -1
  143. package/dist/__tests__/scanner-inventory.test.d.ts +0 -2
  144. package/dist/__tests__/scanner-inventory.test.d.ts.map +0 -1
  145. package/dist/__tests__/scanner-mount-cycle.test.d.ts +0 -2
  146. package/dist/__tests__/scanner-mount-cycle.test.d.ts.map +0 -1
  147. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts +0 -2
  148. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts.map +0 -1
  149. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts +0 -2
  150. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts.map +0 -1
  151. package/dist/__tests__/topology-actions.unit.test.d.ts +0 -2
  152. package/dist/__tests__/topology-actions.unit.test.d.ts.map +0 -1
  153. package/dist/__tests__/topology.unit.test.d.ts +0 -2
  154. package/dist/__tests__/topology.unit.test.d.ts.map +0 -1
  155. package/dist/parameterized-pack-node.d.ts.map +0 -1
  156. package/dist/parameterized-pack-node.mjs.map +0 -1
  157. package/dist/parameterized-pack.d.ts.map +0 -1
@@ -0,0 +1,35 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { dirname, relative, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import ts from 'typescript';
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../');
8
+ const CONFIG_PATH = resolve(REPO_ROOT, 'packages/pack/tsconfig.json');
9
+
10
+ async function declarationProjectInputs(): Promise<readonly string[]> {
11
+ const source = await readFile(CONFIG_PATH, 'utf8');
12
+ const parsed = ts.parseJsonConfigFileContent(
13
+ JSON.parse(source),
14
+ ts.sys,
15
+ dirname(CONFIG_PATH),
16
+ undefined,
17
+ CONFIG_PATH,
18
+ );
19
+ return parsed.fileNames.map((fileName) => relative(REPO_ROOT, fileName));
20
+ }
21
+
22
+ describe('Pack declaration project boundary', () => {
23
+ it('keeps tests and emitted declarations out of production inputs', async () => {
24
+ const inputs = await declarationProjectInputs();
25
+ const config = JSON.parse(await readFile(CONFIG_PATH, 'utf8')) as {
26
+ readonly exclude?: readonly string[];
27
+ };
28
+
29
+ expect(config.exclude).toEqual(expect.arrayContaining(['src/**/__tests__/**', 'dist/**']));
30
+ expect(inputs.some((fileName) => fileName.startsWith('packages/pack/src/__tests__/'))).toBe(
31
+ false,
32
+ );
33
+ expect(inputs.some((fileName) => fileName.startsWith('packages/pack/dist/'))).toBe(false);
34
+ });
35
+ });
@@ -0,0 +1,24 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ const packageRoots = ['packages/pack/src', 'packages/vite-plugin-pack/src', 'packages/render/src'];
6
+
7
+ describe('Surface consumer census', () => {
8
+ it('keeps the runtime and Pack consumers on the existing MaterialAsset wire', async () => {
9
+ const sources = await Promise.all(
10
+ packageRoots.map(async (root) => {
11
+ const path = resolve(process.cwd(), root, 'index.ts');
12
+ try {
13
+ return await readFile(path, 'utf8');
14
+ } catch {
15
+ return '';
16
+ }
17
+ }),
18
+ );
19
+ const source = sources.join('\n');
20
+ expect(source).not.toContain('SurfaceAsset');
21
+ expect(source).not.toContain('surfaceModule');
22
+ expect(source).not.toContain('shadingModel');
23
+ });
24
+ });
@@ -0,0 +1,159 @@
1
+ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
+ import { Materials } from '@forgeax/engine-render';
6
+ import { describe, expect, it } from 'vitest';
7
+ import { NativeCookerRegistry } from '../native-cooker-registry.js';
8
+
9
+ const compilerModule = pathToFileURL(
10
+ resolve(
11
+ dirname(fileURLToPath(import.meta.url)),
12
+ '../../../../packages/shader-compiler/dist/index.mjs',
13
+ ),
14
+ ).href;
15
+
16
+ const GUID = '11111111-1111-4111-8111-111111111111';
17
+ const ROOT_GUID = '22222222-2222-4222-8222-222222222222';
18
+ const CHILD_GUID = '33333333-3333-4333-8333-333333333333';
19
+ const SURFACE = `#define_import_path game_3d::rusted_iron_surface
20
+ #import forgeax_material::surface_v1::{SurfaceData, SurfaceInput}
21
+ fn evaluate_surface(input: SurfaceInput) -> SurfaceData {
22
+ return SurfaceData(vec3<f32>(0.4, 0.45, 0.47), input.geometricNormalWS, 0.0, 0.5, vec3<f32>(0.0), 1.0, 1.0, 0.0);
23
+ }`;
24
+
25
+ describe('Surface Pack publication', () => {
26
+ it('publishes one complete cooked record with source closure and artifact', async () => {
27
+ const root = await mkdtemp(join(tmpdir(), 'forgeax-surface-publication-'));
28
+ try {
29
+ const sourcePath = join(root, 'rusted-iron-surface.wgsl');
30
+ await writeFile(sourcePath, SURFACE);
31
+ const material = Materials.standard({
32
+ surfaceModule: 'game_3d::rusted_iron_surface',
33
+ parameters: [],
34
+ values: {},
35
+ });
36
+ const { createMaterialPackCooker } = await import(compilerModule);
37
+ const draft = await createMaterialPackCooker([root]).cook({
38
+ guid: GUID,
39
+ source: material,
40
+ sourcePath,
41
+ });
42
+ const cooked = draft.payload.cooked as {
43
+ readonly receipt: { readonly sourceClosure: readonly string[] };
44
+ readonly artifact: { readonly path: string; readonly bytes: Uint8Array };
45
+ };
46
+ expect(cooked.receipt.sourceClosure).toContain(sourcePath);
47
+ expect(cooked.artifact.path).toContain(GUID);
48
+ const artifact = draft.artifacts[cooked.artifact.path];
49
+ expect(artifact?.bytes.byteLength).toBeGreaterThan(0);
50
+ expect(Object.keys(draft.artifacts)).toContain(cooked.artifact.path);
51
+ } finally {
52
+ await rm(root, { recursive: true, force: true });
53
+ }
54
+ });
55
+
56
+ it('keeps the accepted generation as last known good after cook failure', async () => {
57
+ const registry = new NativeCookerRegistry();
58
+ registry.register({
59
+ key: 'material',
60
+ cook: async (input: { readonly fail?: boolean }) => {
61
+ if (input.fail) throw new Error('surface compose failed');
62
+ return {
63
+ guid: GUID,
64
+ payload: { generation: 1 },
65
+ refs: [],
66
+ artifacts: {},
67
+ inputFingerprint: 'sha256:surface-input',
68
+ };
69
+ },
70
+ });
71
+ const first = await registry.runTransaction({ key: 'material', input: {} });
72
+ expect(first).toMatchObject({ ok: true, value: { generation: 1, status: 'committed' } });
73
+ if (!first.ok) return;
74
+ const failed = await registry.runTransaction({
75
+ key: 'material',
76
+ input: { fail: true },
77
+ previous: { draft: first.value.draft, generation: first.value.generation },
78
+ });
79
+ expect(failed).toMatchObject({
80
+ ok: true,
81
+ value: {
82
+ status: 'recovered',
83
+ lastKnownGood: { payload: { generation: 1 } },
84
+ lastKnownGoodGeneration: 1,
85
+ },
86
+ });
87
+ });
88
+
89
+ it('cold-cooks a child through the Pack-owned root table and publishes its parent ref', async () => {
90
+ const root = await mkdtemp(join(tmpdir(), 'forgeax-surface-root-child-'));
91
+ try {
92
+ const rootMaterial = Materials.standard({
93
+ baseColor: [1, 1, 1, 1],
94
+ metallic: 0,
95
+ roughness: 0.5,
96
+ });
97
+ const child = {
98
+ kind: 'material' as const,
99
+ parent: ROOT_GUID as never,
100
+ values: { baseColor: [0.4, 0.45, 0.47, 1] },
101
+ };
102
+ const { createMaterialPackCooker } = await import(compilerModule);
103
+ const draft = await createMaterialPackCooker([root]).cook({
104
+ guid: CHILD_GUID,
105
+ source: child,
106
+ table: { [ROOT_GUID]: rootMaterial, [CHILD_GUID]: child },
107
+ });
108
+ const cooked = draft.payload.cooked as {
109
+ readonly authored: { readonly parent?: string };
110
+ readonly resolved: {
111
+ readonly parameters: readonly { readonly name: string }[];
112
+ readonly values: Readonly<Record<string, unknown>>;
113
+ };
114
+ readonly refs: { readonly parent: readonly string[] };
115
+ };
116
+ expect(cooked.authored.parent).toBe(ROOT_GUID);
117
+ expect(cooked.refs.parent).toEqual([ROOT_GUID]);
118
+ expect(cooked.resolved.parameters.map((parameter) => parameter.name)).toContain('baseColor');
119
+ expect(cooked.resolved.values.baseColor).toEqual([0.4, 0.45, 0.47, 1]);
120
+ expect(draft.refs).toContain(ROOT_GUID);
121
+ } finally {
122
+ await rm(root, { recursive: true, force: true });
123
+ }
124
+ });
125
+
126
+ it('does not publish an artifact when a physical material requests Deferred', async () => {
127
+ const { createMaterialPackCooker } = await import(compilerModule);
128
+ const material = {
129
+ kind: 'material' as const,
130
+ passes: [
131
+ {
132
+ name: 'forward',
133
+ program: {
134
+ module: 'forgeax_material::standard',
135
+ moduleSlots: { surface: 'forgeax_material::default_standard_surface' },
136
+ },
137
+ },
138
+ {
139
+ name: 'deferred',
140
+ program: {
141
+ module: 'forgeax_material::standard',
142
+ moduleSlots: { surface: 'forgeax_material::default_standard_surface' },
143
+ },
144
+ },
145
+ ],
146
+ parameters: [
147
+ { name: 'clearcoat', type: 'f32' as const },
148
+ { name: 'clearcoatRoughness', type: 'f32' as const },
149
+ ],
150
+ values: { clearcoat: 0, clearcoatRoughness: 0.5 },
151
+ };
152
+ await expect(
153
+ createMaterialPackCooker().cook({
154
+ guid: GUID,
155
+ source: material,
156
+ }),
157
+ ).rejects.toThrow('material-physical-contract-invalid');
158
+ });
159
+ });
@@ -0,0 +1,30 @@
1
+ import { Materials } from '@forgeax/engine-render';
2
+ import { assertMaterialAsset } from '@forgeax/engine-types';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ const customOptions = {
6
+ surfaceModule: 'game_3d::rusted_iron_surface',
7
+ parameters: [{ name: 'ironColor', type: 'color' as const }],
8
+ values: { ironColor: [0.4, 0.45, 0.47, 1] },
9
+ };
10
+
11
+ describe('custom Surface MaterialAsset wire projection', () => {
12
+ it('uses Standard module and the existing Surface slot wire', () => {
13
+ const material = Materials.standard(customOptions as never);
14
+ expect(material.passes?.map((pass) => pass.program.module)).toEqual([
15
+ 'forgeax_material::standard',
16
+ 'forgeax_material::standard',
17
+ 'forgeax_material::standard',
18
+ ]);
19
+ expect(
20
+ material.passes?.every(
21
+ (pass) => pass.program.moduleSlots?.surface === customOptions.surfaceModule,
22
+ ),
23
+ ).toBe(true);
24
+ const wire = JSON.parse(JSON.stringify(material)) as Record<string, unknown>;
25
+ assertMaterialAsset(wire);
26
+ expect(wire).not.toHaveProperty('surfaceModule');
27
+ expect(wire).not.toHaveProperty('shadingModel');
28
+ expect(wire).not.toHaveProperty('surface');
29
+ });
30
+ });
@@ -3,7 +3,7 @@ import { tmpdir } from 'node:os';
3
3
  import { join } from 'node:path';
4
4
  import { afterEach, describe, expect, it } from 'vitest';
5
5
  import { AssetGuid, PackageId } from '../guid.js';
6
- import { createFileSystemParameterizedPackAuthoringGateway } from '../parameterized-pack-node.js';
6
+ import { createFileSystemPackAuthoringGateway } from '../pack-authoring-node.js';
7
7
 
8
8
  const DIRECT_PACKAGE = '01900000-0000-7000-8000-000000000070';
9
9
  const CLONE_PACKAGE = '01900000-0000-7000-8000-000000000071';
@@ -23,11 +23,11 @@ afterEach(async () => {
23
23
  if (root !== undefined) await rm(root, { recursive: true, force: true });
24
24
  });
25
25
 
26
- describe('parameterized Pack authoring gateway', () => {
26
+ describe('Pack authoring gateway', () => {
27
27
  it('writes guid-less direct JSON, derives identity, and makes mutations idempotent', async () => {
28
28
  const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-gateway-direct-'));
29
29
  roots.push(root);
30
- const gateway = createFileSystemParameterizedPackAuthoringGateway({ gameRoot: root });
30
+ const gateway = createFileSystemPackAuthoringGateway({ gameRoot: root });
31
31
  const operation = {
32
32
  operation: 'asset-source.create' as const,
33
33
  requestId: 'create-direct',
@@ -72,7 +72,7 @@ describe('parameterized Pack authoring gateway', () => {
72
72
  });
73
73
  expect(unresolved).toMatchObject({ ok: false, error: { code: 'asset-not-ready' } });
74
74
 
75
- const publishedGateway = createFileSystemParameterizedPackAuthoringGateway({
75
+ const publishedGateway = createFileSystemPackAuthoringGateway({
76
76
  gameRoot: root,
77
77
  materialized: () => [
78
78
  {
@@ -121,10 +121,10 @@ describe('parameterized Pack authoring gateway', () => {
121
121
  expect(cloneResolved).toMatchObject({ ok: true, value: { status: 'identity' } });
122
122
  });
123
123
 
124
- it('creates parameterized source and instance documents with CAS-protected value edits', async () => {
124
+ it('creates ScriptablePack source and Pack instance documents with CAS-protected value edits', async () => {
125
125
  const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-gateway-instance-'));
126
126
  roots.push(root);
127
- const gateway = createFileSystemParameterizedPackAuthoringGateway({ gameRoot: root });
127
+ const gateway = createFileSystemPackAuthoringGateway({ gameRoot: root });
128
128
  const source = await gateway.execute({
129
129
  operation: 'asset-source.create',
130
130
  requestId: 'create-source',
@@ -188,7 +188,7 @@ describe('parameterized Pack authoring gateway', () => {
188
188
  it('fails closed when the current materialized projection violates derived identity', async () => {
189
189
  const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-gateway-projection-'));
190
190
  roots.push(root);
191
- const gateway = createFileSystemParameterizedPackAuthoringGateway({
191
+ const gateway = createFileSystemPackAuthoringGateway({
192
192
  gameRoot: root,
193
193
  materialized: () => [
194
194
  {
@@ -216,7 +216,7 @@ describe('parameterized Pack authoring gateway', () => {
216
216
  it('does not fall back from a missing sourcePath to another package locator', async () => {
217
217
  const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-gateway-locator-'));
218
218
  roots.push(root);
219
- const gateway = createFileSystemParameterizedPackAuthoringGateway({ gameRoot: root });
219
+ const gateway = createFileSystemPackAuthoringGateway({ gameRoot: root });
220
220
  await gateway.execute({
221
221
  operation: 'asset-source.create',
222
222
  requestId: 'create-locator-source',
@@ -237,7 +237,7 @@ describe('parameterized Pack authoring gateway', () => {
237
237
  it('converts a broken materialized projection callback into a structured error', async () => {
238
238
  const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-gateway-projection-callback-'));
239
239
  roots.push(root);
240
- const gateway = createFileSystemParameterizedPackAuthoringGateway({
240
+ const gateway = createFileSystemPackAuthoringGateway({
241
241
  gameRoot: root,
242
242
  materialized: () => {
243
243
  throw new Error('projection unavailable');
@@ -5,12 +5,12 @@ import {
5
5
  definePack,
6
6
  definePackageId,
7
7
  type PackParameterInheritanceSubject,
8
- parseParameterizedPackJson,
8
+ parsePackSourceJson,
9
9
  projectDirectPackJson,
10
10
  resolvePackParameterInheritance,
11
11
  resolvePackParameterValues,
12
12
  validatePackDefinition,
13
- } from '../parameterized-pack.js';
13
+ } from '../pack-authoring.js';
14
14
 
15
15
  const NAMESPACE = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
16
16
 
@@ -20,7 +20,7 @@ function packageId(value: string) {
20
20
  return result.value;
21
21
  }
22
22
 
23
- describe('parameterized Pack authoring', () => {
23
+ describe('ScriptablePack and Pack authoring', () => {
24
24
  it('derives the RFC 4122 UUIDv5 vector and keeps PackageId branded separately', () => {
25
25
  const namespace = packageId(NAMESPACE);
26
26
  expect(AssetGuid.format(AssetGuid.derive(namespace, 'www.widgets.com'))).toBe(
@@ -30,7 +30,7 @@ describe('parameterized Pack authoring', () => {
30
30
  expect(AssetGuid.derive(namespace, 'mesh/a')).not.toBe(namespace);
31
31
  });
32
32
 
33
- it('derives an explicit context shape for zero-parameter and parameterized Packs', async () => {
33
+ it('derives an explicit context shape for zero-parameter and parameter-bearing ScriptablePacks', async () => {
34
34
  const zero = definePack({
35
35
  schemaVersion: '2.0.0',
36
36
  packageId: definePackageId('01900000-0000-7000-8000-000000000001'),
@@ -51,7 +51,7 @@ describe('parameterized Pack authoring', () => {
51
51
  });
52
52
  expect(zeroResult.ok).toBe(true);
53
53
 
54
- const parameterized = definePack({
54
+ const withParameters = definePack({
55
55
  schemaVersion: '2.0.0',
56
56
  packageId: definePackageId('01900000-0000-7000-8000-000000000002'),
57
57
  parameters: [
@@ -67,9 +67,9 @@ describe('parameterized Pack authoring', () => {
67
67
  },
68
68
  }),
69
69
  });
70
- const values = resolvePackParameterValues(parameterized, { segments: 24 });
70
+ const values = resolvePackParameterValues(withParameters, { segments: 24 });
71
71
  expect(values).toMatchObject({ ok: true, value: { segments: 24, style: 'oak' } });
72
- expect(resolvePackParameterValues(parameterized, { unknown: true })).toMatchObject({
72
+ expect(resolvePackParameterValues(withParameters, { unknown: true })).toMatchObject({
73
73
  ok: false,
74
74
  error: { code: 'pack-parameter-invalid' },
75
75
  });
@@ -148,7 +148,7 @@ describe('parameterized Pack authoring', () => {
148
148
  });
149
149
 
150
150
  it('parses direct and instance JSON without accepting GUID fields', () => {
151
- const direct = parseParameterizedPackJson({
151
+ const direct = parsePackSourceJson({
152
152
  schemaVersion: '3.0.0',
153
153
  packageId: '01900000-0000-7000-8000-000000000010',
154
154
  assets: {
@@ -167,14 +167,14 @@ describe('parameterized Pack authoring', () => {
167
167
  });
168
168
  }
169
169
  expect(
170
- parseParameterizedPackJson({
170
+ parsePackSourceJson({
171
171
  schemaVersion: '3.0.0',
172
172
  packageId: '01900000-0000-7000-8000-000000000010',
173
173
  assets: { 'scene/main': { guid: NAMESPACE, kind: 'scene', payload: {}, refs: [] } },
174
174
  }),
175
175
  ).toMatchObject({ ok: false, error: { code: 'pack-parameter-invalid' } });
176
176
  expect(
177
- parseParameterizedPackJson({
177
+ parsePackSourceJson({
178
178
  schemaVersion: '3.0.0',
179
179
  packageId: '01900000-0000-7000-8000-000000000020',
180
180
  parent: '01900000-0000-7000-8000-000000000002',
@@ -16,9 +16,9 @@ afterEach(async () => {
16
16
  if (root !== undefined) await rm(root, { recursive: true, force: true });
17
17
  });
18
18
 
19
- describe('parameterized Pack scanner', () => {
19
+ describe('ScriptablePack and Pack source scanner', () => {
20
20
  it('indexes direct v3 output keys as derived GUIDs without requiring entry GUIDs', async () => {
21
- const root = await mkdtemp(join(tmpdir(), 'forgeax-parameterized-scan-'));
21
+ const root = await mkdtemp(join(tmpdir(), 'forgeax-scriptable-pack-scan-'));
22
22
  roots.push(root);
23
23
  const path = join(root, 'direct.pack.json');
24
24
  await writeFile(
@@ -65,8 +65,8 @@ describe('parameterized Pack scanner', () => {
65
65
  expect(stderr).toEqual([]);
66
66
  });
67
67
 
68
- it('captures a parameterized source as metadata and resolves an instance parent', async () => {
69
- const root = await mkdtemp(join(tmpdir(), 'forgeax-parameterized-source-scan-'));
68
+ it('captures a ScriptablePack source as metadata and resolves an instance parent', async () => {
69
+ const root = await mkdtemp(join(tmpdir(), 'forgeax-scriptable-pack-source-scan-'));
70
70
  roots.push(root);
71
71
  await writeFile(
72
72
  join(root, 'source.pack.ts'),
@@ -96,12 +96,12 @@ describe('parameterized Pack scanner', () => {
96
96
  expect(result.ok).toBe(true);
97
97
  if (!result.ok) return;
98
98
  const declaration = result.value.declarations.get(join(root, 'source.pack.ts'));
99
- expect(declaration?.format).toBe('pack.ts-parameterized');
99
+ expect(declaration?.format).toBe('pack.ts');
100
100
  expect(result.value.inventory).toEqual([]);
101
101
  });
102
102
 
103
103
  it('fails closed when an instance parent is missing', async () => {
104
- const root = await mkdtemp(join(tmpdir(), 'forgeax-parameterized-parent-scan-'));
104
+ const root = await mkdtemp(join(tmpdir(), 'forgeax-scriptable-pack-parent-scan-'));
105
105
  roots.push(root);
106
106
  await writeFile(
107
107
  join(root, 'missing.pack.json'),
@@ -117,16 +117,14 @@ describe('engine-pack scanner inventory contract', () => {
117
117
  });
118
118
  const scriptableDeclaration = result.value.declarations.get(scriptablePath);
119
119
  expect(scriptableDeclaration).toMatchObject({
120
- format: 'pack.ts-parameterized',
120
+ format: 'pack.ts',
121
121
  sourcePath: scriptablePath,
122
122
  value: {
123
123
  packageId: '019e3969-1d48-7c3b-ac24-6d68f4570662',
124
124
  },
125
125
  });
126
126
  expect(
127
- scriptableDeclaration?.format === 'pack.ts-parameterized'
128
- ? scriptableDeclaration.value
129
- : undefined,
127
+ scriptableDeclaration?.format === 'pack.ts' ? scriptableDeclaration.value : undefined,
130
128
  ).not.toHaveProperty('subAssets');
131
129
  });
132
130
 
@@ -44,11 +44,11 @@ describe('AssetInventory', () => {
44
44
  const { inventory, sourcePath } = getFixture();
45
45
  const declaration = inventory.declarations.get(sourcePath);
46
46
  expect(declaration).toMatchObject({
47
- format: 'pack.ts-parameterized',
47
+ format: 'pack.ts',
48
48
  sourcePath,
49
49
  value: {
50
50
  schemaVersion: '2.0.0',
51
- kind: 'parameterized-pack-source',
51
+ kind: 'scriptable-pack-source',
52
52
  packageId: '00000000-0000-0000-0000-000000000001',
53
53
  source: sourcePath,
54
54
  },
@@ -59,7 +59,7 @@ describe('AssetInventory', () => {
59
59
  const { inventory, sourcePath } = getFixture();
60
60
  const declaration = inventory.declarations.get(sourcePath);
61
61
  expect(
62
- declaration?.format === 'pack.ts-parameterized'
62
+ declaration?.format === 'pack.ts'
63
63
  ? declaration.sourceClosure.map((entry) => entry.path)
64
64
  : undefined,
65
65
  ).toEqual([await realpath(sourcePath)]);
@@ -69,9 +69,10 @@ describe('AssetInventory', () => {
69
69
  const { inventory, sourcePath } = getFixture();
70
70
  const declaration = inventory.declarations.get(sourcePath);
71
71
  expect(inventory.inventory).toEqual([]);
72
- expect(
73
- declaration?.format === 'pack.ts-parameterized' ? declaration.definition : undefined,
74
- ).toMatchObject({ packageId: expect.any(Uint8Array), schemaVersion: '2.0.0' });
72
+ expect(declaration?.format === 'pack.ts' ? declaration.definition : undefined).toMatchObject({
73
+ packageId: expect.any(Uint8Array),
74
+ schemaVersion: '2.0.0',
75
+ });
75
76
  });
76
77
 
77
78
  it('keeps semantic identity stable when the source path is renamed', () => {
@@ -31,7 +31,7 @@ describe('ScriptablePack CLI Meta inspection', () => {
31
31
  expect(code).toBe(0);
32
32
  expect(stderr).toEqual([]);
33
33
  expect(JSON.parse(stdout[0] ?? '{}')).toMatchObject({
34
- kind: 'parameterized-pack-source',
34
+ kind: 'scriptable-pack-source',
35
35
  source,
36
36
  packageId: '019ffa97-8b39-7ad2-84cc-273268591ab4',
37
37
  });
package/src/build.ts CHANGED
@@ -60,6 +60,8 @@ export {
60
60
  type MaterialCookReceipt,
61
61
  type MaterialCookRecordError,
62
62
  type MaterialCookRefs,
63
+ type MaterialCookVariant,
64
+ type MaterialCookVariantContext,
63
65
  projectCookedMaterialRecord,
64
66
  serializeCookedMaterialRecord,
65
67
  serializeMaterialCookReceipt,
@@ -94,6 +96,13 @@ export {
94
96
  type MeshBinHeaderV4,
95
97
  writeMeshBinHeader,
96
98
  } from './mesh-bin-contract.js';
99
+ export * from './pack-authoring.js';
100
+ export {
101
+ createFileSystemPackAuthoringGateway,
102
+ createFileSystemPackAuthoringPort,
103
+ type FileSystemPackAuthoringOptions,
104
+ type PackAuthoringMaterializedAsset,
105
+ } from './pack-authoring-node.js';
97
106
  export {
98
107
  type FinalizedPackageProduct,
99
108
  finalizePackageProduct,
@@ -106,13 +115,6 @@ export {
106
115
  type PackageProductAsset,
107
116
  packageTransportRevision,
108
117
  } from './package-finalizer.js';
109
- export * from './parameterized-pack.js';
110
- export {
111
- createFileSystemParameterizedPackAuthoringGateway,
112
- createFileSystemParameterizedPackAuthoringPort,
113
- type FileSystemParameterizedPackAuthoringOptions,
114
- type ParameterizedPackMaterializedAsset,
115
- } from './parameterized-pack-node.js';
116
118
  export { validateProducerContract, validateProducerOutputs } from './producer-contract.js';
117
119
  export { resolveAssetSource } from './resolve-asset-source.js';
118
120
  export { parsePackV2, validateMeta, validatePack, validatePackV2 } from './runtime.js';
@@ -129,7 +131,7 @@ export {
129
131
  type LegacyPackInventoryDocument,
130
132
  type PackInventoryAsset,
131
133
  type PackInventoryDocument,
132
- type ParameterizedPackInventoryDocument,
134
+ type PackSourceInventoryDocument,
133
135
  type ScanInventory,
134
136
  type ScanOptions,
135
137
  type ScanSourceDeclaration,
@@ -6,7 +6,7 @@ import {
6
6
  projectPackageCatalog,
7
7
  } from './catalog-projection.js';
8
8
  import { deriveAssetName } from './deriveAssetName.js';
9
- import { parseParameterizedPackJson, projectDirectPackJson } from './parameterized-pack.js';
9
+ import { parsePackSourceJson, projectDirectPackJson } from './pack-authoring.js';
10
10
  import { resolveAssetSource } from './resolve-asset-source.js';
11
11
  import {
12
12
  type MetaInventoryDocument,
@@ -201,7 +201,7 @@ function projectSource(
201
201
  declarations: Map<string, CatalogImportMeta>,
202
202
  sourceIdentityFor: CatalogBuildProjectionOptions['sourceIdentityFor'],
203
203
  ): { readonly entries: PackIndexEntry[]; readonly error?: CatalogBuildError } {
204
- if (sourceDeclaration.format === 'pack.ts-parameterized') {
204
+ if (sourceDeclaration.format === 'pack.ts') {
205
205
  // A source declaration is an authoring identity and parameter contract,
206
206
  // not a materialized output set. Dynamic build owns publication after its
207
207
  // fixed-point worklist converges; Catalog scanning must not invent rows.
@@ -233,7 +233,7 @@ function projectSource(
233
233
  const parsed = sourceDeclaration.value;
234
234
  const sourcePath = catalogSourcePathFor(cwd, path, sourceIdentityFor);
235
235
  if (parsed.schemaVersion === '3.0.0') {
236
- const authoring = parseParameterizedPackJson(parsed);
236
+ const authoring = parsePackSourceJson(parsed);
237
237
  if (!authoring.ok) {
238
238
  return {
239
239
  entries: [],
package/src/cli-asset.ts CHANGED
@@ -26,9 +26,9 @@ import {
26
26
  import { readSourceInventory } from './evidence/source-inventory.js';
27
27
  import { isValidAssetGuidString } from './guid.js';
28
28
  import { parsePackV2 } from './index.js';
29
- import { projectParameterizedPackMeta } from './parameterized-pack.js';
29
+ import { projectScriptablePackMeta } from './pack-authoring.js';
30
30
  import { type ScanSourceDeclaration, scanInventory } from './scanner.js';
31
- import { loadParameterizedScriptablePack } from './scriptable-pack-node.js';
31
+ import { loadScriptablePack } from './scriptable-pack-node.js';
32
32
 
33
33
  export interface PackEntry {
34
34
  readonly guid: string;
@@ -81,7 +81,7 @@ export async function scanEntries(
81
81
  return { ok: false };
82
82
  }
83
83
  const entries: PackEntry[] = [];
84
- // The scanner is the single identity projection for Pack JSON. Parameterized
84
+ // The scanner is the single identity projection for Pack JSON. ScriptablePack
85
85
  // source modules deliberately contribute no rows until a build generation.
86
86
  for (const declaration of result.value.declarations.values()) {
87
87
  if (declaration.format !== 'meta.json') continue;
@@ -233,11 +233,11 @@ async function runMeta(rest: string[], ctx: AssetCtx): Promise<number> {
233
233
  });
234
234
  }
235
235
  const cwd = ctx.cwd ?? process.cwd();
236
- const loaded = await loadParameterizedScriptablePack(absolutePath(source, cwd), {
236
+ const loaded = await loadScriptablePack(absolutePath(source, cwd), {
237
237
  metadataOnly: true,
238
238
  });
239
239
  if (!loaded.ok) return emitError(ctx, loaded.error);
240
- ctx.stdoutWrite(JSON.stringify(projectParameterizedPackMeta(loaded.value, source)));
240
+ ctx.stdoutWrite(JSON.stringify(projectScriptablePackMeta(loaded.value, source)));
241
241
  return 0;
242
242
  }
243
243