@forgeax/engine-import 0.1.29 → 0.1.31
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 +15 -0
- package/dist/__tests__/scriptable-pack-fingerprint.unit.test.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-fingerprint.unit.test.d.ts.map +1 -0
- package/dist/build-production.d.ts.map +1 -1
- package/dist/index.mjs +119 -82
- package/dist/index.mjs.map +1 -1
- package/dist/scriptable-pack-build.d.ts.map +1 -1
- package/dist/scriptable-pack-file-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack-fingerprint.d.ts +3 -0
- package/dist/scriptable-pack-fingerprint.d.ts.map +1 -0
- package/dist/scriptable-pack-staged-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack.d.ts +3 -3
- package/dist/scriptable-pack.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/scriptable-pack-build.unit.test.ts +129 -0
- package/src/__tests__/scriptable-pack-fingerprint.unit.test.ts +65 -0
- package/src/build-production.ts +3 -7
- package/src/scriptable-pack-build.ts +74 -32
- package/src/scriptable-pack-file-snapshot.ts +2 -28
- package/src/scriptable-pack-fingerprint.ts +48 -0
- package/src/scriptable-pack-staged-snapshot.ts +2 -22
- package/src/scriptable-pack.ts +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptable-pack-build.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAwB,MAAM,oCAAoC,CAAC;AAC7F,OAAO,EACL,KAAK,2BAA2B,EAIhC,KAAK,kBAAkB,EACvB,SAAS,
|
|
1
|
+
{"version":3,"file":"scriptable-pack-build.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptable-pack-file-snapshot.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-file-snapshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scriptable-pack-file-snapshot.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-file-snapshot.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,iCAAiC,EAClC,MAAM,sBAAsB,CAAC;AAG9B,MAAM,WAAW,4CAA4C;IAC3D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,MAAM,MAAM,oCAAoC,GAC5C;IACE,QAAQ,CAAC,IAAI,EAAE,sCAAsC,CAAC;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,iCAAiC,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,mCAAmC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,8BAA8B,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,SAAS,EAAE,SAAS;YAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC5F,CAAC;CACH,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,qCAAqC,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACvF,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,oCAAoC,CAAC;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5F,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,CAAC;AAkON;;;;GAIG;AACH,wBAAgB,2CAA2C,CACzD,OAAO,EAAE,4CAA4C,GACpD,iCAAiC,CAyBnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scriptable-pack-fingerprint.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-fingerprint.ts"],"names":[],"mappings":"AAGA,oFAAoF;AACpF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2ChE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptable-pack-staged-snapshot.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-staged-snapshot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"scriptable-pack-staged-snapshot.d.ts","sourceRoot":"","sources":["../src/scriptable-pack-staged-snapshot.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,IAAI,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAW,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAEV,iCAAiC,EACjC,yBAAyB,EACzB,0BAA0B,EAC3B,MAAM,sBAAsB,CAAC;AAG9B,MAAM,MAAM,2BAA2B,GACnC,UAAU,GACV,WAAW,GACX,kBAAkB,GAClB,yBAAyB,CAAC;AAE9B,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,KAAK,CACH,MAAM,EAAE,iCAAiC,GACxC,OAAO,CAAC,MAAM,CAAC,SAAS,0BAA0B,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;CACxF;AAED,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAC;IACtD,QAAQ,CAAC,uBAAuB,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;CAC1E;AA0BD;;;GAGG;AACH,wBAAgB,6CAA6C,CAC3D,OAAO,EAAE,mCAAmC,GAC3C,iCAAiC,CA0FnC"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import type { ScriptablePackAssetKind } from '@forgeax/engine-pack';
|
|
2
|
-
import type { AssetReader, PackAuthoringError, ScriptablePackReadError } from '@forgeax/engine-pack/source';
|
|
2
|
+
import type { AssetReader, PackAuthoringError, PackCookSource, ScriptablePackReadError } from '@forgeax/engine-pack/source';
|
|
3
3
|
import type { AnimationGraph, Asset, AssetGuid as AssetGuidType, AssetPublicationEnvelope, FontAsset, ImportError, ImportedAsset, MaterialAsset, MeshAsset, Result, TilesetAsset } from '@forgeax/engine-types';
|
|
4
4
|
import type { ImportAssetProduct, TerminalImportProduct } from './import-product.js';
|
|
5
5
|
export type { ScriptablePackSourceClosureEntry } from '@forgeax/engine-pack/source';
|
|
6
6
|
export interface ScriptablePackAssetSnapshot {
|
|
7
|
-
readonly asset: Asset;
|
|
7
|
+
readonly asset: Asset | PackCookSource;
|
|
8
8
|
readonly generation: number;
|
|
9
9
|
readonly digest: string;
|
|
10
10
|
}
|
|
11
11
|
export interface ScriptablePackStagedOutput {
|
|
12
12
|
readonly guid: AssetGuidType;
|
|
13
13
|
readonly sourceKey: string;
|
|
14
|
-
readonly asset: Asset;
|
|
14
|
+
readonly asset: Asset | PackCookSource;
|
|
15
15
|
readonly digest?: string;
|
|
16
16
|
}
|
|
17
17
|
export interface ScriptablePackAssetSnapshotSource {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptable-pack.d.ts","sourceRoot":"","sources":["../src/scriptable-pack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EACV,cAAc,EACd,KAAK,EACL,SAAS,IAAI,aAAa,EAC1B,wBAAwB,EACxB,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,MAAM,EACN,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAErF,YAAY,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"scriptable-pack.d.ts","sourceRoot":"","sources":["../src/scriptable-pack.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-import",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@forgeax/engine-ddc": "0.1.
|
|
31
|
-
"@forgeax/engine-ecs": "0.1.
|
|
32
|
-
"@forgeax/engine-geometry": "0.1.
|
|
33
|
-
"@forgeax/engine-pack": "0.1.
|
|
34
|
-
"@forgeax/engine-scene": "0.1.
|
|
35
|
-
"@forgeax/engine-shader": "0.1.
|
|
36
|
-
"@forgeax/engine-types": "0.1.
|
|
30
|
+
"@forgeax/engine-ddc": "0.1.31",
|
|
31
|
+
"@forgeax/engine-ecs": "0.1.31",
|
|
32
|
+
"@forgeax/engine-geometry": "0.1.31",
|
|
33
|
+
"@forgeax/engine-pack": "0.1.31",
|
|
34
|
+
"@forgeax/engine-scene": "0.1.31",
|
|
35
|
+
"@forgeax/engine-shader": "0.1.31",
|
|
36
|
+
"@forgeax/engine-types": "0.1.31",
|
|
37
37
|
"@noble/hashes": "^2.2.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
@@ -28,6 +28,135 @@ function producers() {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
describe('ScriptablePack import bridge with optional parameters', () => {
|
|
31
|
+
it('cooks parameterized custom sources alongside ordinary Assets with derived identity and references', async () => {
|
|
32
|
+
const packageId = definePackageId('01900000-0000-7000-8000-000000000049');
|
|
33
|
+
const sceneGuid = AssetGuid.format(AssetGuid.derive(packageId, 'scene/main'));
|
|
34
|
+
const shapeGuid = AssetGuid.format(AssetGuid.derive(packageId, 'shape/custom'));
|
|
35
|
+
const definition = definePack({
|
|
36
|
+
schemaVersion: '2.0.0',
|
|
37
|
+
packageId,
|
|
38
|
+
parameters: [{ name: 'count', type: 'u32', default: 2, minimum: 1 }] as const,
|
|
39
|
+
build: ({ values }) =>
|
|
40
|
+
ok({
|
|
41
|
+
'scene/main': scene(),
|
|
42
|
+
'shape/custom': {
|
|
43
|
+
kind: 'test-volume',
|
|
44
|
+
execution: 'cooked',
|
|
45
|
+
source: { count: values.count, reference: sceneGuid },
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
const inputs: unknown[] = [];
|
|
50
|
+
const cooker = {
|
|
51
|
+
key: 'test-volume',
|
|
52
|
+
cook(raw: unknown) {
|
|
53
|
+
inputs.push(raw);
|
|
54
|
+
const input = raw as { guid: string; source: { count: number; reference: string } };
|
|
55
|
+
return {
|
|
56
|
+
guid: input.guid,
|
|
57
|
+
payload: { kind: 'test-volume', count: input.source.count },
|
|
58
|
+
refs: [input.source.reference],
|
|
59
|
+
artifacts: {
|
|
60
|
+
body: {
|
|
61
|
+
mediaType: 'application/octet-stream',
|
|
62
|
+
bytes: new Uint8Array(input.source.count),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
inputFingerprint: `test-count:${input.source.count}`,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const options = {
|
|
70
|
+
definition,
|
|
71
|
+
sourcePath: 'assets/custom.pack.ts',
|
|
72
|
+
outputs: producers(),
|
|
73
|
+
availableGuids: new Set<string>(),
|
|
74
|
+
};
|
|
75
|
+
const missing = await buildScriptablePack(options);
|
|
76
|
+
expect(missing).toMatchObject({ ok: false, error: { code: 'native-cook-failed' } });
|
|
77
|
+
const first = await buildScriptablePack({
|
|
78
|
+
...options,
|
|
79
|
+
cookers: [cooker],
|
|
80
|
+
values: { count: 3 },
|
|
81
|
+
});
|
|
82
|
+
expect(first.ok).toBe(true);
|
|
83
|
+
if (!first.ok) throw first.error;
|
|
84
|
+
expect(inputs).toEqual([
|
|
85
|
+
{
|
|
86
|
+
guid: shapeGuid,
|
|
87
|
+
sourceKey: 'shape/custom',
|
|
88
|
+
sourcePath: 'assets/custom.pack.ts',
|
|
89
|
+
source: { count: 3, reference: sceneGuid },
|
|
90
|
+
refs: [],
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
93
|
+
const output = first.value.product.assets.find((asset) => asset.guid === shapeGuid);
|
|
94
|
+
expect(output).toMatchObject({
|
|
95
|
+
kind: 'test-volume',
|
|
96
|
+
payload: { kind: 'test-volume', count: 3 },
|
|
97
|
+
refs: [{ guid: sceneGuid }],
|
|
98
|
+
artifacts: { body: { bytes: new Uint8Array(3) } },
|
|
99
|
+
});
|
|
100
|
+
expect(first.value.stagedOutputs.map((output) => output.sourceKey)).toEqual([
|
|
101
|
+
'scene/main',
|
|
102
|
+
'shape/custom',
|
|
103
|
+
]);
|
|
104
|
+
const second = await buildScriptablePack({
|
|
105
|
+
...options,
|
|
106
|
+
cookers: [cooker],
|
|
107
|
+
values: { count: 4 },
|
|
108
|
+
});
|
|
109
|
+
expect(second.ok).toBe(true);
|
|
110
|
+
if (!second.ok) throw second.error;
|
|
111
|
+
expect(
|
|
112
|
+
second.value.product.assets.find((asset) => asset.guid === shapeGuid)?.artifacts.body?.bytes,
|
|
113
|
+
).toEqual(new Uint8Array(4));
|
|
114
|
+
expect(second.value.inputFingerprint).not.toBe(first.value.inputFingerprint);
|
|
115
|
+
const wrongIdentity = await buildScriptablePack({
|
|
116
|
+
...options,
|
|
117
|
+
cookers: [
|
|
118
|
+
{
|
|
119
|
+
...cooker,
|
|
120
|
+
cook(raw: unknown) {
|
|
121
|
+
return { ...cooker.cook(raw), guid: sceneGuid };
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
expect(wrongIdentity).toMatchObject({
|
|
127
|
+
ok: false,
|
|
128
|
+
error: { code: 'pack-source-output-invalid' },
|
|
129
|
+
});
|
|
130
|
+
const published = await produceScriptablePackProducts({
|
|
131
|
+
sources: [
|
|
132
|
+
{
|
|
133
|
+
definition,
|
|
134
|
+
sourcePath: options.sourcePath,
|
|
135
|
+
displaySourcePath: options.sourcePath,
|
|
136
|
+
sourceClosure: [],
|
|
137
|
+
publicationGeneration: 1,
|
|
138
|
+
values: { count: 3 },
|
|
139
|
+
policy: {
|
|
140
|
+
base: '/',
|
|
141
|
+
packagePath: 'assets/custom.pack.json',
|
|
142
|
+
artifactPath: (guid, key) => `artifacts/${guid}/${key}`,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
cookers: [cooker],
|
|
147
|
+
});
|
|
148
|
+
expect(published.ok).toBe(true);
|
|
149
|
+
if (!published.ok) throw published.error;
|
|
150
|
+
const prepared = published.value.get(options.sourcePath);
|
|
151
|
+
if (prepared === undefined) throw new Error('custom source was not published');
|
|
152
|
+
expect(prepared.facts.outputs).toContainEqual(
|
|
153
|
+
expect.objectContaining({ guid: shapeGuid, sourceKey: 'shape/custom', kind: 'test-volume' }),
|
|
154
|
+
);
|
|
155
|
+
expect(
|
|
156
|
+
prepared.finalized.pack.assets.find((asset) => asset.guid === shapeGuid)?.artifacts?.body,
|
|
157
|
+
).toMatchObject({ byteLength: 3, integrity: { algorithm: 'sha256' } });
|
|
158
|
+
});
|
|
159
|
+
|
|
31
160
|
it('uses the subject packageId and dynamic sourceKey output map', async () => {
|
|
32
161
|
const packageId = definePackageId('01900000-0000-7000-8000-000000000040');
|
|
33
162
|
const definition = definePack({
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createMeshBuilder } from '@forgeax/engine-geometry';
|
|
2
|
+
import { definePack, definePackageId } from '@forgeax/engine-pack/source';
|
|
3
|
+
import { ok } from '@forgeax/engine-types';
|
|
4
|
+
import { expect, it, vi } from 'vitest';
|
|
5
|
+
import { AssetOutputProducerRegistry } from '../scriptable-pack.js';
|
|
6
|
+
import { buildScriptablePack } from '../scriptable-pack-build.js';
|
|
7
|
+
import { scriptablePackFingerprint } from '../scriptable-pack-fingerprint.js';
|
|
8
|
+
|
|
9
|
+
it('fingerprints mesh buffers without enumerating a JSON property for every float', async () => {
|
|
10
|
+
const mesh = createMeshBuilder({
|
|
11
|
+
attributes: { position: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]) },
|
|
12
|
+
indices: [0, 1, 2],
|
|
13
|
+
})
|
|
14
|
+
.build()
|
|
15
|
+
.unwrap();
|
|
16
|
+
const outputs = new AssetOutputProducerRegistry();
|
|
17
|
+
outputs.register({
|
|
18
|
+
kind: 'mesh',
|
|
19
|
+
version: 'test',
|
|
20
|
+
produce: () => ok({ payload: mesh, refs: [], artifacts: {} }),
|
|
21
|
+
});
|
|
22
|
+
const definition = definePack({
|
|
23
|
+
schemaVersion: '2.0.0',
|
|
24
|
+
packageId: definePackageId('01900000-0000-7000-8000-000000000089'),
|
|
25
|
+
build: () => ok({ 'mesh/large': mesh }),
|
|
26
|
+
});
|
|
27
|
+
const keys = Object.keys;
|
|
28
|
+
let enumeratedBuffers = 0;
|
|
29
|
+
const spy = vi.spyOn(Object, 'keys').mockImplementation((value) => {
|
|
30
|
+
if (ArrayBuffer.isView(value)) enumeratedBuffers++;
|
|
31
|
+
return keys(value);
|
|
32
|
+
});
|
|
33
|
+
try {
|
|
34
|
+
const result = await buildScriptablePack({ definition, sourcePath: 'large.pack.ts', outputs });
|
|
35
|
+
expect(result.ok).toBe(true);
|
|
36
|
+
expect(enumeratedBuffers).toBe(0);
|
|
37
|
+
} finally {
|
|
38
|
+
spy.mockRestore();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('hashes the selected byte range, type and content with stable object order', () => {
|
|
43
|
+
const values = new Float32Array([99, 1.25, -2, 88]);
|
|
44
|
+
const view = values.subarray(1, 3);
|
|
45
|
+
expect(scriptablePackFingerprint({ z: view, a: 1 })).toBe(
|
|
46
|
+
scriptablePackFingerprint({ a: 1, z: new Float32Array([1.25, -2]) }),
|
|
47
|
+
);
|
|
48
|
+
expect(scriptablePackFingerprint(view)).not.toBe(
|
|
49
|
+
scriptablePackFingerprint(new Uint8Array(view.buffer, view.byteOffset, view.byteLength)),
|
|
50
|
+
);
|
|
51
|
+
const before = scriptablePackFingerprint(view);
|
|
52
|
+
view[1] = 3;
|
|
53
|
+
expect(scriptablePackFingerprint(view)).not.toBe(before);
|
|
54
|
+
expect(scriptablePackFingerprint(new ArrayBuffer(4))).not.toBe(scriptablePackFingerprint({}));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// This checks bounded serialization, not throughput under coverage instrumentation.
|
|
58
|
+
it('streams a representative large mesh buffer without a giant JSON string', () => {
|
|
59
|
+
const vertices = new Float32Array(16 * 1024 * 1024);
|
|
60
|
+
vertices[0] = 1.25;
|
|
61
|
+
vertices[vertices.length - 1] = -2;
|
|
62
|
+
const first = scriptablePackFingerprint({ kind: 'mesh', vertices });
|
|
63
|
+
vertices[vertices.length - 1] = -3;
|
|
64
|
+
expect(scriptablePackFingerprint({ kind: 'mesh', vertices })).not.toBe(first);
|
|
65
|
+
}, 60000);
|
package/src/build-production.ts
CHANGED
|
@@ -109,16 +109,11 @@ function runtimePublicationFor(
|
|
|
109
109
|
...(input.digest === undefined ? {} : { digest: input.digest }),
|
|
110
110
|
...(input.inputFingerprint === undefined ? {} : { inputFingerprint: input.inputFingerprint }),
|
|
111
111
|
...(input.outputs === undefined ? {} : { outputs: input.outputs }),
|
|
112
|
+
...(input.sourceKeys === undefined ? {} : { sourceKeys: input.sourceKeys }),
|
|
112
113
|
...(input.externalEvidence === undefined ? {} : { externalEvidence: input.externalEvidence }),
|
|
113
114
|
generation: context.runtimeBinding?.generation ?? context.generation,
|
|
114
115
|
};
|
|
115
|
-
|
|
116
|
-
const derived = createRuntimePackPublication(publicationInput);
|
|
117
|
-
const outputs = derived.publication.outputs.map((output) => ({
|
|
118
|
-
...output,
|
|
119
|
-
sourceKey: input.sourceKeys?.get(output.guid.toLowerCase()) ?? output.sourceKey,
|
|
120
|
-
}));
|
|
121
|
-
return createRuntimePackPublication({ ...publicationInput, outputs });
|
|
116
|
+
return createRuntimePackPublication(publicationInput);
|
|
122
117
|
}
|
|
123
118
|
|
|
124
119
|
function sourceKeysFor(
|
|
@@ -622,6 +617,7 @@ async function emitAuthoredPack(
|
|
|
622
617
|
};
|
|
623
618
|
const runtimePublication = runtimePublicationFor(work.context, {
|
|
624
619
|
pack: authoredPack,
|
|
620
|
+
sourceKeys: sourceKeysFor(legacy.assets),
|
|
625
621
|
sourcePath: entry.sourcePath,
|
|
626
622
|
sourceRevision: declaration.sourceRevision,
|
|
627
623
|
packageUrl:
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
PackageId,
|
|
10
10
|
type PackBuildContextWithoutParameters,
|
|
11
11
|
type PackBuildContextWithParameters,
|
|
12
|
+
type PackCookSource,
|
|
13
|
+
type PackOutputMap,
|
|
12
14
|
type PackParameterDefinition,
|
|
13
15
|
type PackParameterValue,
|
|
14
16
|
resolvePackParameterValues,
|
|
@@ -38,6 +40,7 @@ import type {
|
|
|
38
40
|
ScriptablePackSourceClosureEntry,
|
|
39
41
|
ScriptablePackStagedOutput,
|
|
40
42
|
} from './scriptable-pack.js';
|
|
43
|
+
import { scriptablePackFingerprint as digest } from './scriptable-pack-fingerprint.js';
|
|
41
44
|
import { materialAssetOutputProducer } from './scriptable-pack-output-producers.js';
|
|
42
45
|
|
|
43
46
|
export interface ScriptablePackBuildOptions {
|
|
@@ -82,7 +85,7 @@ export type ScriptablePackBuildResult = Result<
|
|
|
82
85
|
|
|
83
86
|
interface ObservedRead {
|
|
84
87
|
readonly guid: string;
|
|
85
|
-
readonly asset: Asset;
|
|
88
|
+
readonly asset: Asset | PackCookSource;
|
|
86
89
|
readonly generation: number;
|
|
87
90
|
readonly digest: string;
|
|
88
91
|
}
|
|
@@ -103,35 +106,17 @@ function clone<T>(value: T): T {
|
|
|
103
106
|
return structuredClone(value);
|
|
104
107
|
}
|
|
105
108
|
|
|
106
|
-
function stable(value: unknown): string {
|
|
107
|
-
if (value instanceof Uint8Array) return JSON.stringify(Array.from(value));
|
|
108
|
-
if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
|
|
109
|
-
if (value !== null && typeof value === 'object') {
|
|
110
|
-
const object = value as Record<string, unknown>;
|
|
111
|
-
return `{${Object.keys(object)
|
|
112
|
-
.sort()
|
|
113
|
-
.map((key) => `${JSON.stringify(key)}:${stable(object[key])}`)
|
|
114
|
-
.join(',')}}`;
|
|
115
|
-
}
|
|
116
|
-
return JSON.stringify(value) ?? 'null';
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function digest(value: unknown): Promise<string> {
|
|
120
|
-
const crypto = globalThis.crypto?.subtle;
|
|
121
|
-
if (crypto === undefined) throw new Error('Web Crypto API is required for Pack fingerprints');
|
|
122
|
-
const bytes = await crypto.digest('SHA-256', new TextEncoder().encode(stable(value)));
|
|
123
|
-
return `sha256:${Array.from(new Uint8Array(bytes), (byte) => byte.toString(16).padStart(2, '0')).join('')}`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
109
|
function observedReader(source: ScriptablePackAssetSnapshotSource | undefined): {
|
|
127
110
|
readonly reader: {
|
|
128
|
-
readByGuid<TAsset extends Asset = Asset>(
|
|
111
|
+
readByGuid<TAsset extends Asset | PackCookSource = Asset>(
|
|
112
|
+
guid: AssetGuidType,
|
|
113
|
+
): Promise<Result<TAsset, unknown>>;
|
|
129
114
|
};
|
|
130
115
|
readonly reads: ReadonlyMap<string, ObservedRead>;
|
|
131
116
|
} {
|
|
132
117
|
const reads = new Map<string, ObservedRead>();
|
|
133
118
|
const reader = {
|
|
134
|
-
async readByGuid<TAsset extends Asset = Asset>(
|
|
119
|
+
async readByGuid<TAsset extends Asset | PackCookSource = Asset>(
|
|
135
120
|
guid: AssetGuidType,
|
|
136
121
|
): Promise<Result<TAsset, unknown>> {
|
|
137
122
|
const key = AssetGuid.format(guid).toLowerCase();
|
|
@@ -220,7 +205,7 @@ function referenceError(
|
|
|
220
205
|
function productError(
|
|
221
206
|
sourcePath: string,
|
|
222
207
|
sourceKey: string,
|
|
223
|
-
producer: AssetOutputProducer,
|
|
208
|
+
producer: Pick<AssetOutputProducer, 'kind'>,
|
|
224
209
|
product: unknown,
|
|
225
210
|
): PackAuthoringError | undefined {
|
|
226
211
|
if (!record(product)) {
|
|
@@ -340,9 +325,7 @@ export async function buildScriptablePack(
|
|
|
340
325
|
});
|
|
341
326
|
}
|
|
342
327
|
|
|
343
|
-
let built:
|
|
344
|
-
| Result<Record<string, Asset>, unknown>
|
|
345
|
-
| Promise<Result<Record<string, Asset>, unknown>>;
|
|
328
|
+
let built: Result<PackOutputMap, unknown> | Promise<Result<PackOutputMap, unknown>>;
|
|
346
329
|
try {
|
|
347
330
|
const context = buildContext(subjectPackageId, effectiveValues, observed.reader);
|
|
348
331
|
built = options.definition.build(context as never);
|
|
@@ -394,14 +377,32 @@ export async function buildScriptablePack(
|
|
|
394
377
|
const imported: ImportedAsset<unknown>[] = [];
|
|
395
378
|
const stagedOutputs: ScriptablePackStagedOutput[] = [];
|
|
396
379
|
const localGuids = new Set<string>();
|
|
397
|
-
const
|
|
398
|
-
for (const cooker of options.cookers ?? [])
|
|
380
|
+
const cookerRegistry = new NativeCookerRegistry();
|
|
381
|
+
for (const cooker of options.cookers ?? []) cookerRegistry.register(cooker);
|
|
399
382
|
const nativeFingerprints = new Map<string, string>();
|
|
400
383
|
for (const sourceKey of Object.keys(built.value).sort()) {
|
|
401
384
|
if (!isValidPackSourceKey(sourceKey))
|
|
402
385
|
return err(sourceKeyFailure(options.sourcePath, sourceKey));
|
|
403
386
|
const asset = built.value[sourceKey];
|
|
404
|
-
|
|
387
|
+
const customSource = record(asset) && asset.execution === 'cooked';
|
|
388
|
+
if (
|
|
389
|
+
customSource &&
|
|
390
|
+
(typeof asset.kind !== 'string' ||
|
|
391
|
+
asset.kind.trim().length === 0 ||
|
|
392
|
+
isScriptablePackAssetKind(asset.kind) ||
|
|
393
|
+
!('source' in asset) ||
|
|
394
|
+
Object.keys(asset).some((key) => !['kind', 'execution', 'source'].includes(key)))
|
|
395
|
+
) {
|
|
396
|
+
return err(
|
|
397
|
+
outputValueError(
|
|
398
|
+
options.sourcePath,
|
|
399
|
+
sourceKey,
|
|
400
|
+
'a custom kind with only execution: cooked and source; ordinary Assets use their standard producers',
|
|
401
|
+
asset,
|
|
402
|
+
),
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
if (!customSource && !isAsset(asset)) {
|
|
405
406
|
return err(
|
|
406
407
|
outputValueError(
|
|
407
408
|
options.sourcePath,
|
|
@@ -422,6 +423,47 @@ export async function buildScriptablePack(
|
|
|
422
423
|
});
|
|
423
424
|
}
|
|
424
425
|
localGuids.add(normalizedGuid);
|
|
426
|
+
if (customSource) {
|
|
427
|
+
const cooked = await cookerRegistry.runDraft(asset.kind, {
|
|
428
|
+
guid,
|
|
429
|
+
sourceKey,
|
|
430
|
+
sourcePath: options.sourcePath,
|
|
431
|
+
source: asset.source,
|
|
432
|
+
refs: [],
|
|
433
|
+
});
|
|
434
|
+
if (!cooked.ok) return err(cooked.error);
|
|
435
|
+
if (cooked.value.guid.toLowerCase() !== normalizedGuid)
|
|
436
|
+
return err({
|
|
437
|
+
code: 'pack-source-output-invalid',
|
|
438
|
+
expected: 'the custom cooker to preserve the derived AssetGuid',
|
|
439
|
+
hint: 'remove cooker-owned identity generation and retain the host GUID',
|
|
440
|
+
detail: {
|
|
441
|
+
sourcePath: options.sourcePath,
|
|
442
|
+
sourceKey,
|
|
443
|
+
expectedGuid: guid,
|
|
444
|
+
actualGuid: cooked.value.guid,
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
const product = {
|
|
448
|
+
payload: cooked.value.payload,
|
|
449
|
+
refs: cooked.value.refs.map((guid) => ({ guid })),
|
|
450
|
+
artifacts: cooked.value.artifacts,
|
|
451
|
+
};
|
|
452
|
+
const invalid = productError(options.sourcePath, sourceKey, { kind: asset.kind }, product);
|
|
453
|
+
if (invalid !== undefined) return err(invalid);
|
|
454
|
+
imported.push({ guid, kind: asset.kind, ...product });
|
|
455
|
+
nativeFingerprints.set(sourceKey, cooked.value.inputFingerprint);
|
|
456
|
+
stagedOutputs.push({
|
|
457
|
+
guid: AssetGuid.derive(subjectPackageId, sourceKey),
|
|
458
|
+
sourceKey,
|
|
459
|
+
asset: clone(asset),
|
|
460
|
+
digest: await digest(asset),
|
|
461
|
+
});
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
// A custom source has been handled above; ordinary producers retain the closed Asset union.
|
|
465
|
+
if (!isAsset(asset))
|
|
466
|
+
return err(outputValueError(options.sourcePath, sourceKey, 'an ordinary Asset', asset));
|
|
425
467
|
const producer = options.outputs.get(asset.kind);
|
|
426
468
|
if (producer === undefined) {
|
|
427
469
|
return err(
|
|
@@ -475,8 +517,8 @@ export async function buildScriptablePack(
|
|
|
475
517
|
let payload = product.payload;
|
|
476
518
|
let artifacts = product.artifacts;
|
|
477
519
|
let refs = product.refs;
|
|
478
|
-
if (needsMaterialCook(asset) &&
|
|
479
|
-
const cooked = await
|
|
520
|
+
if (needsMaterialCook(asset) && cookerRegistry.get('material') !== undefined) {
|
|
521
|
+
const cooked = await cookerRegistry.runDraft('material', {
|
|
480
522
|
guid,
|
|
481
523
|
source: asset,
|
|
482
524
|
sourceKey,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
3
2
|
import { resolve } from 'node:path';
|
|
4
3
|
import { isScriptablePackAssetKind, validatePack } from '@forgeax/engine-pack';
|
|
@@ -9,6 +8,7 @@ import type {
|
|
|
9
8
|
ScriptablePackAssetSnapshot,
|
|
10
9
|
ScriptablePackAssetSnapshotSource,
|
|
11
10
|
} from './scriptable-pack.js';
|
|
11
|
+
import { scriptablePackFingerprint as digest } from './scriptable-pack-fingerprint.js';
|
|
12
12
|
|
|
13
13
|
export interface ScriptablePackFileAssetSnapshotSourceOptions {
|
|
14
14
|
readonly assetRoots: readonly string[];
|
|
@@ -90,30 +90,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
90
90
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
function stable(value: unknown): string {
|
|
94
|
-
if (value instanceof ArrayBuffer) {
|
|
95
|
-
return `ArrayBuffer:${JSON.stringify(Array.from(new Uint8Array(value)))}`;
|
|
96
|
-
}
|
|
97
|
-
if (ArrayBuffer.isView(value)) {
|
|
98
|
-
return `${value.constructor.name}:${JSON.stringify(
|
|
99
|
-
Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)),
|
|
100
|
-
)}`;
|
|
101
|
-
}
|
|
102
|
-
if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`;
|
|
103
|
-
if (value !== null && typeof value === 'object') {
|
|
104
|
-
const record = value as Record<string, unknown>;
|
|
105
|
-
return `{${Object.keys(record)
|
|
106
|
-
.sort()
|
|
107
|
-
.map((key) => `${JSON.stringify(key)}:${stable(record[key])}`)
|
|
108
|
-
.join(',')}}`;
|
|
109
|
-
}
|
|
110
|
-
return JSON.stringify(value) ?? 'null';
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function digest(value: unknown): string {
|
|
114
|
-
return `sha256:${createHash('sha256').update(stable(value)).digest('hex')}`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
93
|
function generationFromDigest(value: string): number {
|
|
118
94
|
const parsed = Number.parseInt(value.slice('sha256:'.length, 'sha256:'.length + 8), 16);
|
|
119
95
|
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
@@ -302,9 +278,7 @@ async function indexPackFiles(
|
|
|
302
278
|
}
|
|
303
279
|
}
|
|
304
280
|
|
|
305
|
-
const sourceDigest = digest(
|
|
306
|
-
[...documents].sort((left, right) => stable(left).localeCompare(stable(right))),
|
|
307
|
-
);
|
|
281
|
+
const sourceDigest = digest(documents.map(digest).sort());
|
|
308
282
|
return ok({
|
|
309
283
|
generation: generationFromDigest(sourceDigest),
|
|
310
284
|
assets: byGuid,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
2
|
+
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
3
|
+
|
|
4
|
+
/** One bounded fingerprint encoding for authored, staged and file-backed assets. */
|
|
5
|
+
export function scriptablePackFingerprint(value: unknown): string {
|
|
6
|
+
const hash = sha256.create();
|
|
7
|
+
const encoder = new TextEncoder();
|
|
8
|
+
const text = (part: string) => {
|
|
9
|
+
hash.update(encoder.encode(part));
|
|
10
|
+
};
|
|
11
|
+
const binary = (type: string, bytes: Uint8Array) => {
|
|
12
|
+
// Raw NUL cannot occur in JSON tokens. The type and byte length delimit the
|
|
13
|
+
// binary lane without expanding every float into a sorted JSON property.
|
|
14
|
+
text(`\0${type}:${bytes.byteLength}:`);
|
|
15
|
+
hash.update(bytes);
|
|
16
|
+
text('\0');
|
|
17
|
+
};
|
|
18
|
+
const visit = (item: unknown): void => {
|
|
19
|
+
if (ArrayBuffer.isView(item)) {
|
|
20
|
+
binary(item.constructor.name, new Uint8Array(item.buffer, item.byteOffset, item.byteLength));
|
|
21
|
+
} else if (item instanceof ArrayBuffer) {
|
|
22
|
+
binary('ArrayBuffer', new Uint8Array(item));
|
|
23
|
+
} else if (Array.isArray(item)) {
|
|
24
|
+
text('[');
|
|
25
|
+
for (let i = 0; i < item.length; i++) {
|
|
26
|
+
if (i) text(',');
|
|
27
|
+
visit(item[i]);
|
|
28
|
+
}
|
|
29
|
+
text(']');
|
|
30
|
+
} else if (item !== null && typeof item === 'object') {
|
|
31
|
+
const object = item as Record<string, unknown>;
|
|
32
|
+
text('{');
|
|
33
|
+
let first = true;
|
|
34
|
+
for (const key of Object.keys(object).sort()) {
|
|
35
|
+
if (!first) text(',');
|
|
36
|
+
first = false;
|
|
37
|
+
text(`${JSON.stringify(key)}:`);
|
|
38
|
+
visit(object[key]);
|
|
39
|
+
}
|
|
40
|
+
text('}');
|
|
41
|
+
} else {
|
|
42
|
+
text(JSON.stringify(item) ?? 'null');
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
text('scriptable-pack-fingerprint/2:');
|
|
46
|
+
visit(value);
|
|
47
|
+
return `sha256:${bytesToHex(hash.digest())}`;
|
|
48
|
+
}
|