@flighthq/assets 0.2.1-next.451.d9a4a4e → 0.2.1-next.530.a223ca9
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/dist/assetLibrary.d.ts +3 -2
- package/dist/assetLibrary.d.ts.map +1 -1
- package/dist/assetLibrary.js +102 -14
- package/dist/assetLibrary.js.map +1 -1
- package/package.json +4 -4
- package/src/assetLibrary.test.ts +85 -43
package/dist/assetLibrary.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { AssetGroupLoadOptions, AssetLibrary, AssetLoaderAdapter, AssetManifest, AssetType } from '@flighthq/types';
|
|
1
|
+
import type { AssetDescriptor, AssetGroupLoadOptions, AssetLibrary, AssetLoaderAdapter, AssetManifest, AssetType } from '@flighthq/types';
|
|
2
2
|
export declare function acquireAsset<T = unknown>(library: Readonly<AssetLibrary>, id: string): Promise<T>;
|
|
3
3
|
export declare function createAssetLibrary(): AssetLibrary;
|
|
4
4
|
export declare function disposeAssetLibrary(library: Readonly<AssetLibrary>): void;
|
|
5
5
|
export declare function getAsset<T = unknown>(library: Readonly<AssetLibrary>, id: string): T | null;
|
|
6
6
|
export declare function getAssetRefCount(library: Readonly<AssetLibrary>, id: string): number;
|
|
7
7
|
export declare function loadAssetGroup(library: Readonly<AssetLibrary>, name: string, options?: Readonly<AssetGroupLoadOptions>): Promise<void>;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function registerAssetDescriptor(library: Readonly<AssetLibrary>, descriptor: Readonly<AssetDescriptor>): void;
|
|
9
9
|
export declare function registerAssetLoader<T>(library: Readonly<AssetLibrary>, type: AssetType, adapter: Readonly<AssetLoaderAdapter<T>>): void;
|
|
10
|
+
export declare function registerAssetManifest(library: Readonly<AssetLibrary>, manifest: AssetManifest): void;
|
|
10
11
|
export declare function releaseAsset(library: Readonly<AssetLibrary>, id: string): void;
|
|
11
12
|
export declare function releaseAssetGroup(library: Readonly<AssetLibrary>, name: string): void;
|
|
12
13
|
//# sourceMappingURL=assetLibrary.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetLibrary.d.ts","sourceRoot":"","sources":["../src/assetLibrary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,qBAAqB,EACrB,YAAY,EAEZ,kBAAkB,EAClB,aAAa,EACb,SAAS,EACV,MAAM,iBAAiB,CAAC;AAQzB,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"assetLibrary.d.ts","sourceRoot":"","sources":["../src/assetLibrary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,eAAe,EACf,qBAAqB,EACrB,YAAY,EAEZ,kBAAkB,EAClB,aAAa,EACb,SAAS,EACV,MAAM,iBAAiB,CAAC;AAQzB,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CA2CjG;AAKD,wBAAgB,kBAAkB,IAAI,YAAY,CAQjD;AAID,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,IAAI,CAYzE;AAID,wBAAgB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAG3F;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAGpF;AAQD,wBAAsB,cAAc,CAClC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC,CAqCf;AAMD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,IAAI,CAsBpH;AAKD,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC/B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GACvC,IAAI,CAEN;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAepG;AAKD,wBAAgB,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAO9E;AAKD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrF"}
|
package/dist/assetLibrary.js
CHANGED
|
@@ -10,7 +10,7 @@ export function acquireAsset(library, id) {
|
|
|
10
10
|
const runtime = library.runtime;
|
|
11
11
|
const descriptor = runtime.descriptors.get(id);
|
|
12
12
|
if (descriptor === undefined) {
|
|
13
|
-
return Promise.reject(new Error(`assets: no descriptor for id "${id}" (
|
|
13
|
+
return Promise.reject(new Error(`assets: no descriptor for id "${id}" (registerAssetDescriptor first)`));
|
|
14
14
|
}
|
|
15
15
|
const adapter = runtime.adapters.get(descriptor.type);
|
|
16
16
|
if (adapter === undefined) {
|
|
@@ -36,6 +36,13 @@ export function acquireAsset(library, id) {
|
|
|
36
36
|
entry.resident = true;
|
|
37
37
|
entry.loadPromise = null;
|
|
38
38
|
return value;
|
|
39
|
+
}, (error) => {
|
|
40
|
+
// A failed acquisition owns no resident value and must not poison the id with a permanently
|
|
41
|
+
// rejected promise. Every concurrent holder observes this rejection; a later acquire starts a
|
|
42
|
+
// fresh attempt from the still-registered descriptor.
|
|
43
|
+
if (runtime.entries.get(id) === entry)
|
|
44
|
+
runtime.entries.delete(id);
|
|
45
|
+
throw error;
|
|
39
46
|
});
|
|
40
47
|
entry.loadPromise = loadPromise;
|
|
41
48
|
return loadPromise;
|
|
@@ -84,8 +91,9 @@ export function getAssetRefCount(library, id) {
|
|
|
84
91
|
// Preloads a named group through @flighthq/loader: every member that is not already resident is
|
|
85
92
|
// scheduled as a loader item (bounded concurrency, aggregate progress via options.progress), and every
|
|
86
93
|
// member is acquired (reference count incremented) so the whole group stays resident until
|
|
87
|
-
// releaseAssetGroup. Resolves
|
|
88
|
-
//
|
|
94
|
+
// releaseAssetGroup. Resolves when every member succeeds; rejects with the first member failure after
|
|
95
|
+
// the whole batch settles, while successful members remain held and can be released as one group. A
|
|
96
|
+
// group with no recorded members resolves immediately.
|
|
89
97
|
export async function loadAssetGroup(library, name, options) {
|
|
90
98
|
const runtime = library.runtime;
|
|
91
99
|
const ids = runtime.groups.get(name);
|
|
@@ -98,35 +106,56 @@ export async function loadAssetGroup(library, name, options) {
|
|
|
98
106
|
emitSignal(progress, { loaded, total });
|
|
99
107
|
});
|
|
100
108
|
}
|
|
109
|
+
const itemPromises = [];
|
|
101
110
|
for (const id of ids) {
|
|
102
111
|
const entry = runtime.entries.get(id);
|
|
103
112
|
if (entry !== undefined && entry.resident) {
|
|
104
113
|
// Already loaded — hold a group reference without scheduling a redundant load.
|
|
105
|
-
|
|
114
|
+
itemPromises.push(acquireAsset(library, id));
|
|
106
115
|
continue;
|
|
107
116
|
}
|
|
108
117
|
// Route the actual load through the loader for bounded concurrency; acquireAsset dedups and holds
|
|
109
118
|
// the group's reference.
|
|
110
|
-
queueResourceLoad(loader, () => acquireAsset(library, id));
|
|
119
|
+
itemPromises.push(queueResourceLoad(loader, () => acquireAsset(library, id)).promise);
|
|
111
120
|
}
|
|
121
|
+
// Attach rejection handlers before starting the loader so a fast adapter failure can never surface
|
|
122
|
+
// as an unhandled rejection while the aggregate completion signal is still pending.
|
|
123
|
+
const settlements = Promise.allSettled(itemPromises);
|
|
112
124
|
await new Promise((resolve) => {
|
|
113
125
|
connectSignal(loader.onComplete, () => resolve());
|
|
114
126
|
startResourceLoad(loader);
|
|
115
127
|
});
|
|
128
|
+
const results = await settlements;
|
|
116
129
|
disposeResourceLoader(loader);
|
|
130
|
+
const failed = results.find((result) => result.status === 'rejected');
|
|
131
|
+
if (failed?.status === 'rejected')
|
|
132
|
+
throw failed.reason;
|
|
117
133
|
}
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
134
|
+
// Registers or replaces one catalog descriptor without loading it. Replacement fully reconciles group
|
|
135
|
+
// tags. Replacing an id while it is acquired/in-flight is programmer misuse: the resident value's
|
|
136
|
+
// loader/disposer contract belongs to the descriptor that created it, so changing that contract under
|
|
137
|
+
// live holders would make both get and disposal type-unsafe. An equivalent re-registration is a no-op.
|
|
138
|
+
export function registerAssetDescriptor(library, descriptor) {
|
|
121
139
|
const runtime = library.runtime;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (descriptor
|
|
125
|
-
|
|
126
|
-
|
|
140
|
+
const previous = runtime.descriptors.get(descriptor.id);
|
|
141
|
+
if (previous !== undefined && runtime.entries.has(descriptor.id)) {
|
|
142
|
+
if (isEquivalentAssetDescriptor(previous, descriptor))
|
|
143
|
+
return;
|
|
144
|
+
throw new Error(`assets: cannot replace acquired descriptor "${descriptor.id}" (releaseAsset first)`);
|
|
145
|
+
}
|
|
146
|
+
if (previous !== undefined)
|
|
147
|
+
removeAssetDescriptorGroups(runtime, previous);
|
|
148
|
+
const storedDescriptor = copyAssetDescriptor(descriptor);
|
|
149
|
+
runtime.descriptors.set(descriptor.id, storedDescriptor);
|
|
150
|
+
const groups = storedDescriptor.groups;
|
|
151
|
+
if (groups === undefined)
|
|
152
|
+
return;
|
|
153
|
+
for (let i = 0; i < groups.length; i++) {
|
|
154
|
+
const group = groups[i];
|
|
155
|
+
let members = runtime.groups.get(group);
|
|
127
156
|
if (members === undefined) {
|
|
128
157
|
members = [];
|
|
129
|
-
runtime.groups.set(
|
|
158
|
+
runtime.groups.set(group, members);
|
|
130
159
|
}
|
|
131
160
|
if (!members.includes(descriptor.id))
|
|
132
161
|
members.push(descriptor.id);
|
|
@@ -138,6 +167,25 @@ export function loadAssetManifest(library, manifest) {
|
|
|
138
167
|
export function registerAssetLoader(library, type, adapter) {
|
|
139
168
|
library.runtime.adapters.set(type, adapter);
|
|
140
169
|
}
|
|
170
|
+
// Registers an in-hand plain-data manifest as a batch of descriptor registrations. This is synchronous
|
|
171
|
+
// catalog mutation, not I/O: loadAssetGroup/acquireAsset perform asynchronous work later. Duplicate ids
|
|
172
|
+
// within one manifest use their final descriptor. The batch preflights acquired replacements before
|
|
173
|
+
// mutating anything, so an invalid replacement cannot leave a partially registered manifest.
|
|
174
|
+
export function registerAssetManifest(library, manifest) {
|
|
175
|
+
const descriptors = new Map();
|
|
176
|
+
for (const descriptor of manifest)
|
|
177
|
+
descriptors.set(descriptor.id, descriptor);
|
|
178
|
+
for (const descriptor of descriptors.values()) {
|
|
179
|
+
const previous = library.runtime.descriptors.get(descriptor.id);
|
|
180
|
+
if (previous !== undefined &&
|
|
181
|
+
library.runtime.entries.has(descriptor.id) &&
|
|
182
|
+
!isEquivalentAssetDescriptor(previous, descriptor)) {
|
|
183
|
+
throw new Error(`assets: cannot replace acquired descriptor "${descriptor.id}" (releaseAsset first)`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const descriptor of descriptors.values())
|
|
187
|
+
registerAssetDescriptor(library, descriptor);
|
|
188
|
+
}
|
|
141
189
|
// Decrements the reference count for `id`. When it reaches zero the asset is immediately disposed
|
|
142
190
|
// through its registered adapter and dropped from the cache (deterministic free). Releasing an id that
|
|
143
191
|
// is not held — never acquired, or already freed at zero — is a no-op.
|
|
@@ -173,4 +221,44 @@ function disposeAssetEntry(runtime, id, entry) {
|
|
|
173
221
|
if (adapter !== undefined)
|
|
174
222
|
adapter.dispose(entry.value);
|
|
175
223
|
}
|
|
224
|
+
function copyAssetDescriptor(descriptor) {
|
|
225
|
+
const groups = descriptor.groups;
|
|
226
|
+
return {
|
|
227
|
+
id: descriptor.id,
|
|
228
|
+
type: descriptor.type,
|
|
229
|
+
url: descriptor.url,
|
|
230
|
+
...(groups === undefined ? {} : { groups: [...new Set(groups)] }),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function isEquivalentAssetDescriptor(a, b) {
|
|
234
|
+
if (a.id !== b.id || a.type !== b.type || a.url !== b.url)
|
|
235
|
+
return false;
|
|
236
|
+
const aGroups = a.groups ?? [];
|
|
237
|
+
const bGroups = b.groups ?? [];
|
|
238
|
+
const aUniqueGroups = new Set(aGroups);
|
|
239
|
+
const bUniqueGroups = new Set(bGroups);
|
|
240
|
+
if (aUniqueGroups.size !== bUniqueGroups.size)
|
|
241
|
+
return false;
|
|
242
|
+
for (let i = 0; i < aGroups.length; i++) {
|
|
243
|
+
if (!bUniqueGroups.has(aGroups[i]))
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
function removeAssetDescriptorGroups(runtime, descriptor) {
|
|
249
|
+
const groups = descriptor.groups;
|
|
250
|
+
if (groups === undefined)
|
|
251
|
+
return;
|
|
252
|
+
for (let i = 0; i < groups.length; i++) {
|
|
253
|
+
const group = groups[i];
|
|
254
|
+
const members = runtime.groups.get(group);
|
|
255
|
+
if (members === undefined)
|
|
256
|
+
continue;
|
|
257
|
+
const index = members.indexOf(descriptor.id);
|
|
258
|
+
if (index >= 0)
|
|
259
|
+
members.splice(index, 1);
|
|
260
|
+
if (members.length === 0)
|
|
261
|
+
runtime.groups.delete(group);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
176
264
|
//# sourceMappingURL=assetLibrary.js.map
|
package/dist/assetLibrary.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetLibrary.js","sourceRoot":"","sources":["../src/assetLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"assetLibrary.js","sourceRoot":"","sources":["../src/assetLibrary.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/assets",
|
|
3
|
-
"version": "0.2.1-next.
|
|
3
|
+
"version": "0.2.1-next.530.a223ca9",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@flighthq/loader": "0.2.1-next.
|
|
36
|
-
"@flighthq/signals": "0.2.1-next.
|
|
37
|
-
"@flighthq/types": "0.2.1-next.
|
|
35
|
+
"@flighthq/loader": "0.2.1-next.530.a223ca9",
|
|
36
|
+
"@flighthq/signals": "0.2.1-next.530.a223ca9",
|
|
37
|
+
"@flighthq/types": "0.2.1-next.530.a223ca9"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"typescript": "^5.3.0"
|
package/src/assetLibrary.test.ts
CHANGED
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
getAsset,
|
|
10
10
|
getAssetRefCount,
|
|
11
11
|
loadAssetGroup,
|
|
12
|
-
|
|
12
|
+
registerAssetDescriptor,
|
|
13
13
|
registerAssetLoader,
|
|
14
|
+
registerAssetManifest,
|
|
14
15
|
releaseAsset,
|
|
15
16
|
releaseAssetGroup,
|
|
16
17
|
} from './assetLibrary';
|
|
@@ -68,7 +69,7 @@ function libraryWith(id: string, type = 'image') {
|
|
|
68
69
|
const library = createAssetLibrary();
|
|
69
70
|
const mock = createMockAdapter();
|
|
70
71
|
registerAssetLoader(library, type, mock.adapter);
|
|
71
|
-
|
|
72
|
+
registerAssetManifest(library, [{ id, url: `${id}.bin`, type }]);
|
|
72
73
|
return { library, mock };
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -78,6 +79,24 @@ function tick(): Promise<void> {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
describe('acquireAsset', () => {
|
|
82
|
+
it('drops a rejected entry so a later acquire retries', async () => {
|
|
83
|
+
const library = createAssetLibrary();
|
|
84
|
+
let attempts = 0;
|
|
85
|
+
registerAssetLoader(library, 'image', {
|
|
86
|
+
dispose(): void {},
|
|
87
|
+
load(): Promise<{ id: string }> {
|
|
88
|
+
attempts++;
|
|
89
|
+
return attempts === 1 ? Promise.reject(new Error('temporary')) : Promise.resolve({ id: 'hero' });
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
registerAssetDescriptor(library, { id: 'hero', type: 'image', url: 'hero.bin' });
|
|
93
|
+
|
|
94
|
+
await expect(acquireAsset(library, 'hero')).rejects.toThrow('temporary');
|
|
95
|
+
await expect(acquireAsset(library, 'hero')).resolves.toEqual({ id: 'hero' });
|
|
96
|
+
expect(attempts).toBe(2);
|
|
97
|
+
expect(getAssetRefCount(library, 'hero')).toBe(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
81
100
|
it('resolves the adapter loaded value and calls load once', async () => {
|
|
82
101
|
const { library, mock } = libraryWith('hero');
|
|
83
102
|
const promise = acquireAsset<{ id: string }>(library, 'hero');
|
|
@@ -107,7 +126,7 @@ describe('acquireAsset', () => {
|
|
|
107
126
|
|
|
108
127
|
it('rejects when no adapter is registered for the descriptor type', async () => {
|
|
109
128
|
const library = createAssetLibrary();
|
|
110
|
-
|
|
129
|
+
registerAssetManifest(library, [{ id: 'hero', url: 'hero.bin', type: 'image' }]);
|
|
111
130
|
await expect(acquireAsset(library, 'hero')).rejects.toThrow(/no loader/);
|
|
112
131
|
});
|
|
113
132
|
});
|
|
@@ -184,30 +203,14 @@ describe('loadAssetGroup', () => {
|
|
|
184
203
|
},
|
|
185
204
|
};
|
|
186
205
|
registerAssetLoader(library, 'image', adapter);
|
|
187
|
-
|
|
188
|
-
{ id: 'ok-1', url: 'ok-1.bin', type: 'image',
|
|
189
|
-
{ id: 'bad', url: 'bad.bin', type: 'image',
|
|
190
|
-
{ id: 'ok-2', url: 'ok-2.bin', type: 'image',
|
|
206
|
+
registerAssetManifest(library, [
|
|
207
|
+
{ id: 'ok-1', url: 'ok-1.bin', type: 'image', groups: ['mixed'] },
|
|
208
|
+
{ id: 'bad', url: 'bad.bin', type: 'image', groups: ['mixed'] },
|
|
209
|
+
{ id: 'ok-2', url: 'ok-2.bin', type: 'image', groups: ['mixed'] },
|
|
191
210
|
]);
|
|
192
211
|
failNextId = 'bad';
|
|
193
212
|
|
|
194
|
-
|
|
195
|
-
// failure. That handle is void'd by loadAssetGroup (error-policy: continue), so the rejection
|
|
196
|
-
// surfaces as an unhandled rejection. Suppress it for this test.
|
|
197
|
-
const rejections: unknown[] = [];
|
|
198
|
-
const capture = (reason: unknown) => {
|
|
199
|
-
rejections.push(reason);
|
|
200
|
-
};
|
|
201
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
|
-
(globalThis as any).process.on('unhandledRejection', capture);
|
|
203
|
-
|
|
204
|
-
await loadAssetGroup(library, 'mixed');
|
|
205
|
-
// Drain the microtask queue so the rejection fires within the listener's window.
|
|
206
|
-
await tick();
|
|
207
|
-
|
|
208
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
209
|
-
(globalThis as any).process.removeListener('unhandledRejection', capture);
|
|
210
|
-
expect(rejections).toHaveLength(1);
|
|
213
|
+
await expect(loadAssetGroup(library, 'mixed')).rejects.toThrow('load failed: bad');
|
|
211
214
|
|
|
212
215
|
expect(getAsset(library, 'ok-1')).toEqual({ id: 'ok-1' });
|
|
213
216
|
expect(getAsset(library, 'ok-2')).toEqual({ id: 'ok-2' });
|
|
@@ -225,9 +228,9 @@ describe('loadAssetGroup', () => {
|
|
|
225
228
|
id: `tile-${i}`,
|
|
226
229
|
url: `tile-${i}.bin`,
|
|
227
230
|
type: 'image',
|
|
228
|
-
|
|
231
|
+
groups: ['level'],
|
|
229
232
|
}));
|
|
230
|
-
|
|
233
|
+
registerAssetManifest(library, manifest);
|
|
231
234
|
|
|
232
235
|
const ticks: AssetLoadProgress[] = [];
|
|
233
236
|
const progress = createSignal<(p: Readonly<AssetLoadProgress>) => void>();
|
|
@@ -264,23 +267,42 @@ describe('loadAssetGroup', () => {
|
|
|
264
267
|
});
|
|
265
268
|
});
|
|
266
269
|
|
|
267
|
-
describe('
|
|
268
|
-
it('
|
|
270
|
+
describe('registerAssetDescriptor', () => {
|
|
271
|
+
it('copies caller-owned group data into the catalog', () => {
|
|
272
|
+
const library = createAssetLibrary();
|
|
273
|
+
const groups = ['boot'];
|
|
274
|
+
registerAssetDescriptor(library, { groups, id: 'hero', type: 'image', url: 'hero.bin' });
|
|
275
|
+
groups.push('mutated');
|
|
276
|
+
|
|
277
|
+
expect(library.runtime.descriptors.get('hero')?.groups).toEqual(['boot']);
|
|
278
|
+
expect(library.runtime.groups.has('mutated')).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('moves replacement group membership instead of retaining stale groups', () => {
|
|
282
|
+
const library = createAssetLibrary();
|
|
283
|
+
registerAssetDescriptor(library, { id: 'hero', url: 'hero-a.bin', type: 'image', groups: ['boot', 'shared'] });
|
|
284
|
+
registerAssetDescriptor(library, { id: 'hero', url: 'hero-b.bin', type: 'image', groups: ['level', 'shared'] });
|
|
285
|
+
|
|
286
|
+
expect(library.runtime.groups.get('boot')).toBeUndefined();
|
|
287
|
+
expect(library.runtime.groups.get('level')).toEqual(['hero']);
|
|
288
|
+
expect(library.runtime.groups.get('shared')).toEqual(['hero']);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('rejects changing an acquired descriptor but permits equivalent registration', async () => {
|
|
269
292
|
const library = createAssetLibrary();
|
|
270
293
|
const mock = createMockAdapter();
|
|
271
294
|
registerAssetLoader(library, 'image', mock.adapter);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
expect(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
295
|
+
const descriptor = { id: 'hero', url: 'hero.bin', type: 'image' as const, groups: ['boot'] };
|
|
296
|
+
registerAssetDescriptor(library, descriptor);
|
|
297
|
+
const pending = acquireAsset(library, 'hero');
|
|
298
|
+
|
|
299
|
+
expect(() => registerAssetDescriptor(library, { ...descriptor, groups: ['boot'] })).not.toThrow();
|
|
300
|
+
expect(() => registerAssetDescriptor(library, { ...descriptor, url: 'replacement.bin' })).toThrow(
|
|
301
|
+
/cannot replace acquired descriptor/,
|
|
302
|
+
);
|
|
303
|
+
|
|
281
304
|
mock.flush();
|
|
282
|
-
await
|
|
283
|
-
expect(getAsset(library, 'a')).toEqual({ id: 'a' });
|
|
305
|
+
await pending;
|
|
284
306
|
});
|
|
285
307
|
});
|
|
286
308
|
|
|
@@ -291,7 +313,7 @@ describe('registerAssetLoader', () => {
|
|
|
291
313
|
const second = createMockAdapter();
|
|
292
314
|
registerAssetLoader(library, 'image', first.adapter);
|
|
293
315
|
registerAssetLoader(library, 'image', second.adapter);
|
|
294
|
-
|
|
316
|
+
registerAssetManifest(library, [{ id: 'hero', url: 'hero.bin', type: 'image' }]);
|
|
295
317
|
const promise = acquireAsset(library, 'hero');
|
|
296
318
|
second.flush();
|
|
297
319
|
await promise;
|
|
@@ -300,6 +322,26 @@ describe('registerAssetLoader', () => {
|
|
|
300
322
|
});
|
|
301
323
|
});
|
|
302
324
|
|
|
325
|
+
describe('registerAssetManifest', () => {
|
|
326
|
+
it('records descriptors and group membership without loading', async () => {
|
|
327
|
+
const library = createAssetLibrary();
|
|
328
|
+
const mock = createMockAdapter();
|
|
329
|
+
registerAssetLoader(library, 'image', mock.adapter);
|
|
330
|
+
registerAssetManifest(library, [
|
|
331
|
+
{ id: 'a', url: 'a.bin', type: 'image', groups: ['boot'] },
|
|
332
|
+
{ id: 'b', url: 'b.bin', type: 'image', groups: ['boot'] },
|
|
333
|
+
]);
|
|
334
|
+
// Nothing loaded from recording alone.
|
|
335
|
+
expect(mock.loadCalls).toBe(0);
|
|
336
|
+
expect(getAsset(library, 'a')).toBeNull();
|
|
337
|
+
// The recorded descriptor makes acquire resolvable.
|
|
338
|
+
const promise = acquireAsset(library, 'a');
|
|
339
|
+
mock.flush();
|
|
340
|
+
await promise;
|
|
341
|
+
expect(getAsset(library, 'a')).toEqual({ id: 'a' });
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
303
345
|
describe('releaseAsset', () => {
|
|
304
346
|
it('disposes the orphaned value when released while the load is still in flight', async () => {
|
|
305
347
|
const { library, mock } = libraryWith('hero');
|
|
@@ -366,9 +408,9 @@ describe('releaseAssetGroup', () => {
|
|
|
366
408
|
const library = createAssetLibrary();
|
|
367
409
|
const mock = createMockAdapter();
|
|
368
410
|
registerAssetLoader(library, 'image', mock.adapter);
|
|
369
|
-
|
|
370
|
-
{ id: 'a', url: 'a.bin', type: 'image',
|
|
371
|
-
{ id: 'b', url: 'b.bin', type: 'image',
|
|
411
|
+
registerAssetManifest(library, [
|
|
412
|
+
{ id: 'a', url: 'a.bin', type: 'image', groups: ['level'] },
|
|
413
|
+
{ id: 'b', url: 'b.bin', type: 'image', groups: ['level'] },
|
|
372
414
|
]);
|
|
373
415
|
|
|
374
416
|
const done = loadAssetGroup(library, 'level');
|