@forgeax/engine-pack 0.1.21 → 0.1.24
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 +167 -48
- package/dist/__tests__/inventory-schema.test.d.ts +2 -0
- package/dist/__tests__/inventory-schema.test.d.ts.map +1 -0
- package/dist/__tests__/material-cook-receipt-layer-plan.unit.test.d.ts +2 -0
- package/dist/__tests__/material-cook-receipt-layer-plan.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pack-authoring-gateway.unit.test.d.ts +2 -0
- package/dist/__tests__/pack-authoring-gateway.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pack-authoring.unit.test.d.ts +2 -0
- package/dist/__tests__/pack-authoring.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pack-scanner.unit.test.d.ts +2 -0
- package/dist/__tests__/pack-scanner.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scanner-blacklist.test.d.ts +2 -0
- package/dist/__tests__/scanner-blacklist.test.d.ts.map +1 -0
- package/dist/build.d.ts +9 -4
- package/dist/build.d.ts.map +1 -1
- package/dist/build.mjs +3449 -897
- package/dist/build.mjs.map +1 -1
- package/dist/builtin.mjs +37 -4
- package/dist/builtin.mjs.map +1 -1
- package/dist/catalog-builder.d.ts.map +1 -1
- package/dist/cli-asset.d.ts.map +1 -1
- package/dist/cli-asset.mjs +1361 -845
- package/dist/cli-asset.mjs.map +1 -1
- package/dist/deriveAssetName.d.ts +11 -7
- package/dist/deriveAssetName.d.ts.map +1 -1
- package/dist/evidence/material-cook.d.ts +11 -0
- package/dist/evidence/material-cook.d.ts.map +1 -1
- package/dist/evidence/source-inventory.d.ts.map +1 -1
- package/dist/guid.d.ts +15 -0
- package/dist/guid.d.ts.map +1 -1
- package/dist/guid.mjs +53 -5
- package/dist/guid.mjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +1297 -562
- package/dist/index.mjs.map +1 -1
- package/dist/inventory/binding.d.ts +6 -0
- package/dist/inventory/binding.d.ts.map +1 -0
- package/dist/inventory/declaration.d.ts +24 -0
- package/dist/inventory/declaration.d.ts.map +1 -0
- package/dist/inventory/index.d.ts +3 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/sync.d.ts +5 -0
- package/dist/inventory/sync.d.ts.map +1 -0
- package/dist/material-cook.d.ts +1 -1
- package/dist/material-cook.d.ts.map +1 -1
- package/dist/material-cook.mjs +50 -3
- package/dist/material-cook.mjs.map +1 -1
- package/dist/name.mjs +4 -7
- package/dist/name.mjs.map +1 -1
- package/dist/pack-authoring-node.d.ts +26 -0
- package/dist/pack-authoring-node.d.ts.map +1 -0
- package/dist/pack-authoring-node.mjs +11089 -0
- package/dist/pack-authoring-node.mjs.map +1 -0
- package/dist/pack-authoring.d.ts +230 -0
- package/dist/pack-authoring.d.ts.map +1 -0
- package/dist/pack-authoring.mjs +1137 -0
- package/dist/pack-authoring.mjs.map +1 -0
- package/dist/package-finalizer.d.ts +2 -20
- package/dist/package-finalizer.d.ts.map +1 -1
- package/dist/resolve-asset-source.d.ts +1 -3
- package/dist/resolve-asset-source.d.ts.map +1 -1
- package/dist/resolve-asset-source.mjs +6 -81
- package/dist/resolve-asset-source.mjs.map +1 -1
- package/dist/runtime.mjs +77 -7
- package/dist/runtime.mjs.map +1 -1
- package/dist/scanner.d.ts +18 -7
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.mjs +1164 -687
- package/dist/scanner.mjs.map +1 -1
- package/dist/schema-compiled.d.ts.map +1 -1
- package/dist/schema.mjs +79 -7
- package/dist/schema.mjs.map +1 -1
- package/dist/scriptable-pack-node.d.ts +7 -31
- package/dist/scriptable-pack-node.d.ts.map +1 -1
- package/dist/scriptable-pack-node.mjs +572 -1019
- package/dist/scriptable-pack-node.mjs.map +1 -1
- package/dist/scriptable-pack-worker.mjs +29 -11
- package/dist/scriptable-pack-worker.mjs.map +1 -1
- package/dist/scriptable-pack.d.ts +20 -532
- package/dist/scriptable-pack.d.ts.map +1 -1
- package/dist/scriptable-pack.mjs +1038 -527
- package/dist/scriptable-pack.mjs.map +1 -1
- package/package.json +2 -7
- package/schema/meta.schema.json +1 -1
- package/schema/pack.schema.json +76 -6
- package/src/__tests__/guid-collision.unit.test.ts +18 -9
- package/src/__tests__/inventory-schema.test.ts +109 -0
- package/src/__tests__/material-cook-receipt-layer-plan.unit.test.ts +16 -0
- package/src/__tests__/material-cook-schema.unit.test.ts +62 -0
- package/src/__tests__/pack-authoring-gateway.unit.test.ts +249 -0
- package/src/__tests__/pack-authoring.unit.test.ts +266 -0
- package/src/__tests__/pack-scanner.unit.test.ts +123 -0
- package/src/__tests__/pack.unit.test.ts +1 -238
- package/src/__tests__/package-finalizer.contract.test.ts +55 -0
- package/src/__tests__/resolve-asset-source.test.ts +15 -98
- package/src/__tests__/scanner-blacklist.test.ts +55 -0
- package/src/__tests__/scanner-inventory.contract.test.ts +11 -14
- package/src/__tests__/scanner-inventory.test.ts +23 -10
- package/src/__tests__/scriptable-pack-cli.integration.test.ts +4 -9
- package/src/__tests__/topology.unit.test.ts +23 -0
- package/src/build.ts +28 -18
- package/src/catalog-builder.ts +60 -33
- package/src/cli-asset.ts +68 -83
- package/src/deriveAssetName.ts +14 -13
- package/src/evidence/material-cook.ts +79 -3
- package/src/evidence/source-inventory.ts +34 -21
- package/src/guid.ts +65 -4
- package/src/index.ts +15 -11
- package/src/inventory/binding.ts +25 -0
- package/src/inventory/declaration.ts +168 -0
- package/src/inventory/index.ts +18 -0
- package/src/inventory/sync.ts +22 -0
- package/src/material-cook.ts +1 -0
- package/src/pack-authoring-node.ts +1966 -0
- package/src/pack-authoring.ts +1478 -0
- package/src/package-finalizer.ts +2 -42
- package/src/resolve-asset-source.ts +4 -76
- package/src/scanner.ts +236 -56
- package/src/schema/material-cook.schema.json +4 -1
- package/src/schema-compiled.ts +2 -0
- package/src/scriptable-pack-node.ts +108 -719
- package/src/scriptable-pack-worker.ts +48 -16
- package/src/scriptable-pack.ts +28 -939
- package/dist/.tsbuildinfo +0 -1
- package/dist/__tests__/load-asset-config.test.d.ts +0 -2
- package/dist/__tests__/load-asset-config.test.d.ts.map +0 -1
- package/dist/__tests__/scriptable-pack.test-d.d.ts +0 -2
- package/dist/__tests__/scriptable-pack.test-d.d.ts.map +0 -1
- package/dist/__tests__/scriptable-pack.unit.test.d.ts +0 -2
- package/dist/__tests__/scriptable-pack.unit.test.d.ts.map +0 -1
- package/dist/config.d.ts +0 -6
- package/dist/config.d.ts.map +0 -1
- package/dist/config.mjs +0 -29
- package/dist/config.mjs.map +0 -1
- package/src/__tests__/load-asset-config.test.ts +0 -121
- package/src/__tests__/scriptable-pack.test-d.ts +0 -131
- package/src/__tests__/scriptable-pack.unit.test.ts +0 -789
- package/src/config.ts +0 -36
|
@@ -102,4 +102,59 @@ describe('engine-pack terminal product and finalizer contract', () => {
|
|
|
102
102
|
expect(published.assets[0]?.artifacts.body.byteLength).toBe(body.byteLength);
|
|
103
103
|
expect(writes.get(`${GUID}/body.bin`)).toBe(body);
|
|
104
104
|
});
|
|
105
|
+
|
|
106
|
+
it('publishes a mesh LOD relation and keeps the lower mesh in the closure', async () => {
|
|
107
|
+
const lodGuid = '019e3969-1d48-7c3b-ac24-6d68f4570660';
|
|
108
|
+
const root = product().assets[0];
|
|
109
|
+
if (root === undefined) throw new Error('test product asset is missing');
|
|
110
|
+
const result = await finalizePackageProduct(
|
|
111
|
+
product({
|
|
112
|
+
assets: [
|
|
113
|
+
{
|
|
114
|
+
...root,
|
|
115
|
+
kind: 'mesh',
|
|
116
|
+
payload: {
|
|
117
|
+
kind: 'mesh',
|
|
118
|
+
lods: [{ mesh: lodGuid, screenCoverage: 0.5 }],
|
|
119
|
+
},
|
|
120
|
+
refs: [lodGuid],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
...root,
|
|
124
|
+
guid: lodGuid,
|
|
125
|
+
kind: 'mesh',
|
|
126
|
+
payload: { kind: 'mesh' },
|
|
127
|
+
refs: [],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
receipts: [
|
|
131
|
+
{
|
|
132
|
+
guid: GUID,
|
|
133
|
+
origin: 'sourceMeta',
|
|
134
|
+
status: 'succeeded',
|
|
135
|
+
inputFingerprint: 'sha256:source',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
guid: lodGuid,
|
|
139
|
+
origin: 'sourceMeta',
|
|
140
|
+
status: 'succeeded',
|
|
141
|
+
inputFingerprint: 'sha256:source',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
}),
|
|
145
|
+
{
|
|
146
|
+
base: '/',
|
|
147
|
+
packagePath: 'mesh.pack.json',
|
|
148
|
+
artifactPath: (guid, key) => `${guid}/${key}.bin`,
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
expect(result.ok).toBe(true);
|
|
152
|
+
if (!result.ok) return;
|
|
153
|
+
const publishedRoot = result.value.pack.assets.find((asset) => asset.guid === GUID);
|
|
154
|
+
expect(publishedRoot?.refs).toEqual([lodGuid]);
|
|
155
|
+
expect(publishedRoot?.payload).toMatchObject({
|
|
156
|
+
lods: [{ mesh: lodGuid, screenCoverage: 0.5 }],
|
|
157
|
+
});
|
|
158
|
+
expect(result.value.pack.assets.map((asset) => asset.guid)).toContain(lodGuid);
|
|
159
|
+
});
|
|
105
160
|
});
|
|
@@ -1,31 +1,16 @@
|
|
|
1
|
-
// @ts-nocheck — PackErrorDetail is a discriminated union narrowed by runtime .code
|
|
2
|
-
// checks; TS cannot follow the narrowing through PackError.detail.
|
|
3
1
|
import { resolve } from 'node:path';
|
|
4
2
|
import { describe, expect, it } from 'vitest';
|
|
5
3
|
import { resolveAssetSource } from '../resolve-asset-source.js';
|
|
6
4
|
|
|
7
|
-
describe('resolveAssetSource —
|
|
5
|
+
describe('resolveAssetSource — companion and sidecar-relative sources', () => {
|
|
8
6
|
const metaDir = '/project/assets';
|
|
9
7
|
|
|
10
|
-
it('omitted source
|
|
8
|
+
it('derives an omitted source from the companion filename', () => {
|
|
11
9
|
const metaPath = resolve(metaDir, 'foo.png.meta.json');
|
|
12
|
-
|
|
13
|
-
expect(result.ok).toBe(true);
|
|
14
|
-
if (result.ok) {
|
|
15
|
-
expect(result.value).toBe(resolve(metaDir, 'foo.png'));
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('renamed audio meta derives correct companion (AC-3)', () => {
|
|
20
|
-
const metaPath = resolve(metaDir, 'bleep.wav.meta.json');
|
|
21
|
-
const result = resolveAssetSource(metaPath, undefined, {});
|
|
22
|
-
expect(result.ok).toBe(true);
|
|
23
|
-
if (result.ok) {
|
|
24
|
-
expect(result.value).toBe(resolve(metaDir, 'bleep.wav'));
|
|
25
|
-
}
|
|
10
|
+
expect(resolveAssetSource(metaPath, undefined)).toBe(resolve(metaDir, 'foo.png'));
|
|
26
11
|
});
|
|
27
12
|
|
|
28
|
-
it('
|
|
13
|
+
it('supports every ordinary companion extension without a special table', () => {
|
|
29
14
|
const cases = [
|
|
30
15
|
{ meta: 'model.glb.meta.json', expected: 'model.glb' },
|
|
31
16
|
{ meta: 'sprite.png.meta.json', expected: 'sprite.png' },
|
|
@@ -33,89 +18,21 @@ describe('resolveAssetSource — omit derivation (w4)', () => {
|
|
|
33
18
|
{ meta: 'bgm.mp3.meta.json', expected: 'bgm.mp3' },
|
|
34
19
|
];
|
|
35
20
|
for (const { meta, expected } of cases) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (result.ok) {
|
|
40
|
-
expect(result.value).toBe(resolve(metaDir, expected));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('resolveAssetSource — @name/ path + boundary + legacy (w5)', () => {
|
|
47
|
-
const metaDir = '/project/assets';
|
|
48
|
-
const metaPath = resolve(metaDir, 'foo.png.meta.json');
|
|
49
|
-
|
|
50
|
-
it('resolves @name/rest to absolute path via paths table (AC-5)', () => {
|
|
51
|
-
const paths = { shared: '/lib/assets' };
|
|
52
|
-
const result = resolveAssetSource(metaPath, '@shared/foo.png', paths);
|
|
53
|
-
expect(result.ok).toBe(true);
|
|
54
|
-
if (result.ok) {
|
|
55
|
-
expect(result.value).toBe(resolve('/lib/assets', 'foo.png'));
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('returns pack-unknown-path for undeclared @name (AC-8)', () => {
|
|
60
|
-
const paths = { shared: '/lib/assets' };
|
|
61
|
-
const result = resolveAssetSource(metaPath, '@nope/x.png', paths);
|
|
62
|
-
expect(result.ok).toBe(false);
|
|
63
|
-
if (!result.ok) {
|
|
64
|
-
expect(result.error.code).toBe('pack-unknown-path');
|
|
65
|
-
expect(result.error.detail.pathName).toBe('nope');
|
|
66
|
-
expect(result.error.detail.knownNames).toEqual(['shared']);
|
|
21
|
+
expect(resolveAssetSource(resolve(metaDir, meta), undefined)).toBe(
|
|
22
|
+
resolve(metaDir, expected),
|
|
23
|
+
);
|
|
67
24
|
}
|
|
68
25
|
});
|
|
69
26
|
|
|
70
|
-
it('
|
|
71
|
-
const
|
|
72
|
-
expect(
|
|
73
|
-
if (!result.ok) {
|
|
74
|
-
expect(result.error.code).toBe('pack-malformed-path-ref');
|
|
75
|
-
expect(result.error.detail.rawSource).toBe('@');
|
|
76
|
-
if (result.error.detail.code === 'pack-malformed-path-ref') {
|
|
77
|
-
expect(result.error.detail.reason).toBe('format');
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('returns pack-malformed-path-ref for @onlyname with no /rest (AC-9)', () => {
|
|
83
|
-
const result = resolveAssetSource(metaPath, '@onlyname', { shared: '/lib/assets' });
|
|
84
|
-
expect(result.ok).toBe(false);
|
|
85
|
-
if (!result.ok) {
|
|
86
|
-
expect(result.error.code).toBe('pack-malformed-path-ref');
|
|
87
|
-
expect(result.error.detail.rawSource).toBe('@onlyname');
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('returns pack-malformed-path-ref for ../ escape (AC-11)', () => {
|
|
92
|
-
const paths = { shared: '/data/shared' };
|
|
93
|
-
const result = resolveAssetSource(metaPath, '@shared/../escape.png', paths);
|
|
94
|
-
expect(result.ok).toBe(false);
|
|
95
|
-
if (!result.ok) {
|
|
96
|
-
expect(result.error.code).toBe('pack-malformed-path-ref');
|
|
97
|
-
expect(result.error.detail.rawSource).toBe('@shared/../escape.png');
|
|
98
|
-
if (result.error.detail.code === 'pack-malformed-path-ref') {
|
|
99
|
-
expect(result.error.detail.reason).toBe('escape');
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('resolves legacy relative path unchanged', () => {
|
|
105
|
-
const result = resolveAssetSource(metaPath, 'sub/foo.png', {});
|
|
106
|
-
expect(result.ok).toBe(true);
|
|
107
|
-
if (result.ok) {
|
|
108
|
-
expect(result.value).toBe(resolve(metaDir, 'sub/foo.png'));
|
|
109
|
-
}
|
|
27
|
+
it('resolves an explicit source relative to its sidecar', () => {
|
|
28
|
+
const metaPath = resolve(metaDir, 'foo.png.meta.json');
|
|
29
|
+
expect(resolveAssetSource(metaPath, 'sub/foo.png')).toBe(resolve(metaDir, 'sub/foo.png'));
|
|
110
30
|
});
|
|
111
31
|
|
|
112
|
-
it('
|
|
113
|
-
const
|
|
114
|
-
expect(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
expect(result.error.detail.pathName).toBe('any');
|
|
118
|
-
expect(result.error.detail.knownNames).toEqual([]);
|
|
119
|
-
}
|
|
32
|
+
it('keeps source resolution independent of package.json and path aliases', () => {
|
|
33
|
+
const metaPath = resolve(metaDir, 'foo.png.meta.json');
|
|
34
|
+
expect(resolveAssetSource(metaPath, '@shared/foo.png')).toBe(
|
|
35
|
+
resolve(metaDir, '@shared/foo.png'),
|
|
36
|
+
);
|
|
120
37
|
});
|
|
121
38
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { scan } from '../scanner.js';
|
|
6
|
+
|
|
7
|
+
const EMPTY_PACK = JSON.stringify({
|
|
8
|
+
schemaVersion: '1.0.0',
|
|
9
|
+
kind: 'internal-text-package',
|
|
10
|
+
assets: [],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('asset scanner test-directory boundary', () => {
|
|
14
|
+
const temporaryRoots: string[] = [];
|
|
15
|
+
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await Promise.all(
|
|
18
|
+
temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('skips arbitrarily nested __tests__ declarations while keeping normal assets', async () => {
|
|
23
|
+
const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-scanner-tests-'));
|
|
24
|
+
temporaryRoots.push(root);
|
|
25
|
+
const visible = join(root, 'world', 'scene.pack.json');
|
|
26
|
+
const nestedFixture = join(root, 'world', '__tests__', 'fixture.pack.json');
|
|
27
|
+
const rootFixture = join(root, '__tests__', 'nested', 'fixture.pack.json');
|
|
28
|
+
|
|
29
|
+
await mkdir(join(root, 'world', '__tests__'), { recursive: true });
|
|
30
|
+
await mkdir(join(root, '__tests__', 'nested'), { recursive: true });
|
|
31
|
+
await writeFile(visible, EMPTY_PACK);
|
|
32
|
+
// Deliberately malformed: a test fixture must not be able to degrade the
|
|
33
|
+
// production scan simply because it lives below the asset root.
|
|
34
|
+
await writeFile(nestedFixture, '{}');
|
|
35
|
+
await writeFile(rootFixture, '{}');
|
|
36
|
+
|
|
37
|
+
const result = await scan([root]);
|
|
38
|
+
|
|
39
|
+
expect(result).toMatchObject({ ok: true, value: [visible] });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('allows an explicit __tests__ root when a test intentionally opts in', async () => {
|
|
43
|
+
const root = await mkdtemp(join(tmpdir(), 'forgeax-pack-scanner-tests-'));
|
|
44
|
+
temporaryRoots.push(root);
|
|
45
|
+
const testRoot = join(root, '__tests__');
|
|
46
|
+
const fixture = join(testRoot, 'fixture.pack.json');
|
|
47
|
+
|
|
48
|
+
await mkdir(testRoot, { recursive: true });
|
|
49
|
+
await writeFile(fixture, EMPTY_PACK);
|
|
50
|
+
|
|
51
|
+
const result = await scan([testRoot]);
|
|
52
|
+
|
|
53
|
+
expect(result).toMatchObject({ ok: true, value: [fixture] });
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -88,17 +88,14 @@ describe('engine-pack scanner inventory contract', () => {
|
|
|
88
88
|
await writeFile(scriptablePath, '// scanner fixture');
|
|
89
89
|
|
|
90
90
|
const scriptablePackageId = guid('019e3969-1d48-7c3b-ac24-6d68f4570662');
|
|
91
|
-
const scriptableAssetGuid = guid('019e3969-1d48-7c3b-ac24-6d68f4570663');
|
|
92
91
|
const result = await scanInventory([root], {
|
|
93
92
|
scriptablePack: {
|
|
94
93
|
executor: {
|
|
95
94
|
load: async () => ({
|
|
96
95
|
default: {
|
|
97
|
-
schemaVersion: '
|
|
96
|
+
schemaVersion: '2.0.0',
|
|
98
97
|
packageId: scriptablePackageId,
|
|
99
|
-
|
|
100
|
-
externalAssets: {},
|
|
101
|
-
build: () => ({ ok: true, value: {} }),
|
|
98
|
+
build: () => ({ ok: true, value: { effect: { kind: 'scene', entities: [] } } }),
|
|
102
99
|
},
|
|
103
100
|
}),
|
|
104
101
|
},
|
|
@@ -123,14 +120,12 @@ describe('engine-pack scanner inventory contract', () => {
|
|
|
123
120
|
format: 'pack.ts',
|
|
124
121
|
sourcePath: scriptablePath,
|
|
125
122
|
value: {
|
|
126
|
-
importer: 'pack-ts',
|
|
127
123
|
packageId: '019e3969-1d48-7c3b-ac24-6d68f4570662',
|
|
128
|
-
subAssets: [{ sourceKey: 'effect', kind: 'scene' }],
|
|
129
124
|
},
|
|
130
125
|
});
|
|
131
126
|
expect(
|
|
132
|
-
scriptableDeclaration?.format === 'pack.ts' ? scriptableDeclaration.
|
|
133
|
-
).
|
|
127
|
+
scriptableDeclaration?.format === 'pack.ts' ? scriptableDeclaration.value : undefined,
|
|
128
|
+
).not.toHaveProperty('subAssets');
|
|
134
129
|
});
|
|
135
130
|
|
|
136
131
|
it('releases the ScriptablePack loader for the path-only scan contract', async () => {
|
|
@@ -140,18 +135,15 @@ describe('engine-pack scanner inventory contract', () => {
|
|
|
140
135
|
await writeFile(scriptablePath, '// scanner fixture');
|
|
141
136
|
|
|
142
137
|
const packageId = guid('019e3969-1d48-7c3b-ac24-6d68f4570664');
|
|
143
|
-
const assetGuid = guid('019e3969-1d48-7c3b-ac24-6d68f4570665');
|
|
144
138
|
let disposals = 0;
|
|
145
139
|
const result = await scan([root], {
|
|
146
140
|
scriptablePack: {
|
|
147
141
|
executor: {
|
|
148
142
|
load: async () => ({
|
|
149
143
|
default: {
|
|
150
|
-
schemaVersion: '
|
|
144
|
+
schemaVersion: '2.0.0',
|
|
151
145
|
packageId,
|
|
152
|
-
|
|
153
|
-
externalAssets: {},
|
|
154
|
-
build: () => ({ ok: true, value: {} }),
|
|
146
|
+
build: () => ({ ok: true, value: { effect: { kind: 'scene', entities: [] } } }),
|
|
155
147
|
},
|
|
156
148
|
}),
|
|
157
149
|
dispose: async () => {
|
|
@@ -164,4 +156,9 @@ describe('engine-pack scanner inventory contract', () => {
|
|
|
164
156
|
expect(result.ok).toBe(true);
|
|
165
157
|
expect(disposals).toBe(1);
|
|
166
158
|
});
|
|
159
|
+
|
|
160
|
+
it('characterizes the public scanner inventory vocabulary', () => {
|
|
161
|
+
expect(typeof scan).toBe('function');
|
|
162
|
+
expect(typeof scanInventory).toBe('function');
|
|
163
|
+
});
|
|
167
164
|
});
|
|
@@ -2,6 +2,7 @@ import { mkdtemp, realpath, rm, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
5
|
+
import { inventoryDigest } from '../inventory/sync.js';
|
|
5
6
|
import { scanInventory } from '../scanner.js';
|
|
6
7
|
|
|
7
8
|
describe('AssetInventory', () => {
|
|
@@ -18,11 +19,8 @@ describe('AssetInventory', () => {
|
|
|
18
19
|
[
|
|
19
20
|
'const packageId = new Uint8Array(16);',
|
|
20
21
|
'packageId[15] = 1;',
|
|
21
|
-
'const meshGuid = new Uint8Array(16);',
|
|
22
|
-
'meshGuid[15] = 2;',
|
|
23
22
|
'export default {',
|
|
24
|
-
"schemaVersion: '
|
|
25
|
-
"assets: { mesh: { guid: meshGuid, kind: 'mesh' } }, externalAssets: {},",
|
|
23
|
+
"schemaVersion: '2.0.0', packageId,",
|
|
26
24
|
"build: () => ({ ok: true, value: { mesh: { kind: 'mesh' } } }),",
|
|
27
25
|
'};',
|
|
28
26
|
].join('\n'),
|
|
@@ -48,9 +46,11 @@ describe('AssetInventory', () => {
|
|
|
48
46
|
expect(declaration).toMatchObject({
|
|
49
47
|
format: 'pack.ts',
|
|
50
48
|
sourcePath,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
value: {
|
|
50
|
+
schemaVersion: '2.0.0',
|
|
51
|
+
kind: 'scriptable-pack-source',
|
|
52
|
+
packageId: '00000000-0000-0000-0000-000000000001',
|
|
53
|
+
source: sourcePath,
|
|
54
54
|
},
|
|
55
55
|
});
|
|
56
56
|
});
|
|
@@ -69,8 +69,21 @@ describe('AssetInventory', () => {
|
|
|
69
69
|
const { inventory, sourcePath } = getFixture();
|
|
70
70
|
const declaration = inventory.declarations.get(sourcePath);
|
|
71
71
|
expect(inventory.inventory).toEqual([]);
|
|
72
|
-
expect(declaration?.format === 'pack.ts' ? declaration.
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
expect(declaration?.format === 'pack.ts' ? declaration.definition : undefined).toMatchObject({
|
|
73
|
+
packageId: expect.any(Uint8Array),
|
|
74
|
+
schemaVersion: '2.0.0',
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('keeps semantic identity stable when the source path is renamed', () => {
|
|
79
|
+
const before = inventoryDigest({
|
|
80
|
+
declarations: [{ guid, sourceKey: 'hero/body', kind: 'mesh', payload: {}, refs: [] }],
|
|
81
|
+
});
|
|
82
|
+
const after = inventoryDigest({
|
|
83
|
+
declarations: [{ guid, sourceKey: 'hero/body', kind: 'mesh', payload: {}, refs: [] }],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(after).toBe(before);
|
|
87
|
+
expect(after).not.toContain('generated.pack.ts');
|
|
75
88
|
});
|
|
76
89
|
});
|
|
@@ -14,14 +14,9 @@ describe('ScriptablePack CLI Meta inspection', () => {
|
|
|
14
14
|
await writeFile(
|
|
15
15
|
source,
|
|
16
16
|
`
|
|
17
|
-
const guid = (hex) => new Uint8Array(hex.match(/../g).map((byte) => Number.parseInt(byte, 16)));
|
|
18
17
|
export default {
|
|
19
|
-
schemaVersion: '
|
|
20
|
-
packageId:
|
|
21
|
-
assets: {
|
|
22
|
-
wall: { guid: guid('019ffa97a5ee7645b613043323952808'), kind: 'mesh' }
|
|
23
|
-
},
|
|
24
|
-
externalAssets: {},
|
|
18
|
+
schemaVersion: '2.0.0',
|
|
19
|
+
packageId: new Uint8Array([1, 159, 250, 151, 139, 57, 122, 210, 132, 204, 39, 50, 104, 89, 26, 180]),
|
|
25
20
|
build() { throw new Error('META_MUST_NOT_BUILD'); }
|
|
26
21
|
};
|
|
27
22
|
`,
|
|
@@ -36,9 +31,9 @@ describe('ScriptablePack CLI Meta inspection', () => {
|
|
|
36
31
|
expect(code).toBe(0);
|
|
37
32
|
expect(stderr).toEqual([]);
|
|
38
33
|
expect(JSON.parse(stdout[0] ?? '{}')).toMatchObject({
|
|
39
|
-
|
|
34
|
+
kind: 'scriptable-pack-source',
|
|
40
35
|
source,
|
|
41
|
-
|
|
36
|
+
packageId: '019ffa97-8b39-7ad2-84cc-273268591ab4',
|
|
42
37
|
});
|
|
43
38
|
} finally {
|
|
44
39
|
await rm(root, { recursive: true, force: true });
|
|
@@ -82,4 +82,27 @@ describe('diffTopology', () => {
|
|
|
82
82
|
expect(result.preserved).toEqual([]);
|
|
83
83
|
expect(result.ambiguous).toMatchObject([{ reason: 'duplicate-source-key' }]);
|
|
84
84
|
});
|
|
85
|
+
|
|
86
|
+
it('keeps LOD source keys prefix-stable while allowing a suffix level', () => {
|
|
87
|
+
const result = diffTopology(
|
|
88
|
+
[
|
|
89
|
+
{ guid: 'root', sourceKey: 'mesh/root', sourceIndex: 0, kind: 'mesh' },
|
|
90
|
+
{ guid: 'lod1', sourceKey: 'mesh/lod1', sourceIndex: 1, kind: 'mesh' },
|
|
91
|
+
],
|
|
92
|
+
[
|
|
93
|
+
{ guid: 'root-next', sourceKey: 'mesh/root', sourceIndex: 0, kind: 'mesh' },
|
|
94
|
+
{ guid: 'lod1-next', sourceKey: 'mesh/lod1', sourceIndex: 1, kind: 'mesh' },
|
|
95
|
+
{ guid: 'lod2-next', sourceKey: 'mesh/lod2', sourceIndex: 2, kind: 'mesh' },
|
|
96
|
+
],
|
|
97
|
+
);
|
|
98
|
+
expect(result.preserved).toEqual([
|
|
99
|
+
{ guid: 'root', oldKey: 'mesh/root', newKey: 'mesh/root' },
|
|
100
|
+
{ guid: 'lod1', oldKey: 'mesh/lod1', newKey: 'mesh/lod1' },
|
|
101
|
+
]);
|
|
102
|
+
expect(result.added).toEqual([
|
|
103
|
+
{ guid: 'lod2-next', sourceKey: 'mesh/lod2', sourceIndex: 2, kind: 'mesh' },
|
|
104
|
+
]);
|
|
105
|
+
expect(result.removed).toEqual([]);
|
|
106
|
+
expect(result.ambiguous).toEqual([]);
|
|
107
|
+
});
|
|
85
108
|
});
|
package/src/build.ts
CHANGED
|
@@ -51,7 +51,6 @@ export {
|
|
|
51
51
|
projectRuntimeCatalogRow,
|
|
52
52
|
type RuntimeCatalogRowInput,
|
|
53
53
|
} from './catalog-projection.js';
|
|
54
|
-
export { type LoadAssetConfigResult, loadAssetConfig } from './config.js';
|
|
55
54
|
export {
|
|
56
55
|
type CookedMaterialRecord,
|
|
57
56
|
collectMaterialCookRefs,
|
|
@@ -68,6 +67,22 @@ export {
|
|
|
68
67
|
validateMaterialCookReceipt,
|
|
69
68
|
} from './evidence/material-cook.js';
|
|
70
69
|
export { buildOfflineAssetEvidence, packageVerification } from './evidence/offline-evidence.js';
|
|
70
|
+
export {
|
|
71
|
+
AssetGuid,
|
|
72
|
+
isValidAssetGuidString,
|
|
73
|
+
isValidPackSourceKey,
|
|
74
|
+
PACK_SOURCE_KEY_RE,
|
|
75
|
+
PackageId,
|
|
76
|
+
} from './guid.js';
|
|
77
|
+
export { projectAssetRefs, projectSceneEntityRefs } from './inventory/binding.js';
|
|
78
|
+
export {
|
|
79
|
+
type AuthorInventory,
|
|
80
|
+
type AuthorInventoryRow,
|
|
81
|
+
type InventoryError,
|
|
82
|
+
type InventoryErrorCode,
|
|
83
|
+
validateAuthorInventory,
|
|
84
|
+
} from './inventory/declaration.js';
|
|
85
|
+
export { inventoryDigest, syncAuthorInventory } from './inventory/sync.js';
|
|
71
86
|
export {
|
|
72
87
|
decodeMeshBinHeader,
|
|
73
88
|
MESH_BIN_DIGEST_BYTES,
|
|
@@ -79,9 +94,14 @@ export {
|
|
|
79
94
|
type MeshBinHeaderV4,
|
|
80
95
|
writeMeshBinHeader,
|
|
81
96
|
} from './mesh-bin-contract.js';
|
|
97
|
+
export * from './pack-authoring.js';
|
|
98
|
+
export {
|
|
99
|
+
createFileSystemPackAuthoringGateway,
|
|
100
|
+
createFileSystemPackAuthoringPort,
|
|
101
|
+
type FileSystemPackAuthoringOptions,
|
|
102
|
+
type PackAuthoringMaterializedAsset,
|
|
103
|
+
} from './pack-authoring-node.js';
|
|
82
104
|
export {
|
|
83
|
-
type AuthoredPackAssetInput,
|
|
84
|
-
type AuthoredPackInput,
|
|
85
105
|
type FinalizedPackageProduct,
|
|
86
106
|
finalizePackageProduct,
|
|
87
107
|
finalizePackageTransportSource,
|
|
@@ -92,7 +112,6 @@ export {
|
|
|
92
112
|
type PackageProduct,
|
|
93
113
|
type PackageProductAsset,
|
|
94
114
|
packageTransportRevision,
|
|
95
|
-
upgradeLegacyAuthoredPack,
|
|
96
115
|
} from './package-finalizer.js';
|
|
97
116
|
export { validateProducerContract, validateProducerOutputs } from './producer-contract.js';
|
|
98
117
|
export { resolveAssetSource } from './resolve-asset-source.js';
|
|
@@ -107,8 +126,13 @@ export {
|
|
|
107
126
|
} from './runtime-publication.js';
|
|
108
127
|
export {
|
|
109
128
|
type InventoryDeclaration,
|
|
129
|
+
type LegacyPackInventoryDocument,
|
|
130
|
+
type PackInventoryAsset,
|
|
131
|
+
type PackInventoryDocument,
|
|
132
|
+
type PackSourceInventoryDocument,
|
|
110
133
|
type ScanInventory,
|
|
111
134
|
type ScanOptions,
|
|
135
|
+
type ScanSourceDeclaration,
|
|
112
136
|
type ScriptablePackInventoryDeclaration,
|
|
113
137
|
type ScriptablePackScanOptions,
|
|
114
138
|
STANDARD_SCRIPTABLE_PACK_SCAN_OPTIONS,
|
|
@@ -117,24 +141,10 @@ export {
|
|
|
117
141
|
export {
|
|
118
142
|
type AssetReader,
|
|
119
143
|
isScriptablePackAssetKind,
|
|
120
|
-
projectScriptablePackMeta,
|
|
121
144
|
projectScriptablePackSceneComponents,
|
|
122
145
|
SCRIPTABLE_PACK_ASSET_KINDS,
|
|
123
|
-
SCRIPTABLE_PACK_CAPABILITY_MANIFEST,
|
|
124
|
-
type ScriptablePackAssetDeclaration,
|
|
125
|
-
type ScriptablePackAssetDeclarations,
|
|
126
|
-
type ScriptablePackAssetFor,
|
|
127
146
|
type ScriptablePackAssetKind,
|
|
128
|
-
type ScriptablePackDefinition,
|
|
129
|
-
type ScriptablePackError,
|
|
130
|
-
type ScriptablePackExternalAssets,
|
|
131
|
-
type ScriptablePackMetaJson,
|
|
132
|
-
type ScriptablePackOutputs,
|
|
133
|
-
type ScriptablePackPublicationEnvelope,
|
|
134
147
|
type ScriptablePackReadError,
|
|
135
|
-
type ScriptablePackSceneComponent,
|
|
136
|
-
type ScriptablePackSceneComponentInput,
|
|
137
148
|
type ScriptablePackSourceClosureEntry,
|
|
138
|
-
validateScriptablePackDefinition,
|
|
139
149
|
} from './scriptable-pack.js';
|
|
140
150
|
export { calculateTopologyDiff, diffTopology } from './topology.js';
|