@kubohiroya/turbowarp-asset-cache 0.6.0 → 0.6.1
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.ja.md +7 -2
- package/README.md +2 -2
- package/dist/asset-cache.js +22 -6
- package/dist/composition.js +42 -11
- package/dist/types/composition.d.ts +16 -0
- package/dist/types/extension.d.ts +7 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -54,6 +54,11 @@ Standalone拡張機能を使います。
|
|
|
54
54
|
importし、registryを内部に閉じたまま、パレットへAsset Cacheのblockを追加したくない場合はComposition APIを
|
|
55
55
|
使います。
|
|
56
56
|
|
|
57
|
+
独立したプレビューVMでは、`createAssetManagerComposition.supportsRuntimeIsolation === true`を確認し、
|
|
58
|
+
`createAssetManagerComposition(undefined, {runtime: previewVm.runtime})`で描画とイベント購読の所有先を指定します。
|
|
59
|
+
省略時は従来どおり拡張機能のホストruntimeを使います。終了時の`releaseAll()`は、そのcompositionが所有する
|
|
60
|
+
`STOP_FOR_TARGET`購読も解除します。同じcompositionへ再登録すると必要な購読を再開します。
|
|
61
|
+
|
|
57
62
|
## 動作条件と安全性
|
|
58
63
|
|
|
59
64
|
standaloneでの利用には、TurboWarp Desktop、またはunsandboxedなカスタム拡張機能を読み込める他の
|
|
@@ -83,14 +88,14 @@ SVG入力は既定で拒否します。remote binaryのcache entryは、保存
|
|
|
83
88
|
versionを付けたnpm packageにも、同じレビュー済みビルドが入っています。
|
|
84
89
|
|
|
85
90
|
```bash
|
|
86
|
-
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.6.
|
|
91
|
+
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.6.1
|
|
87
92
|
```
|
|
88
93
|
|
|
89
94
|
`node_modules/@kubohiroya/turbowarp-asset-cache/dist/asset-cache.js`を読み込むか、version固定の
|
|
90
95
|
CDN URLを使います。
|
|
91
96
|
|
|
92
97
|
```text
|
|
93
|
-
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.6.
|
|
98
|
+
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.6.1/dist/asset-cache.js
|
|
94
99
|
```
|
|
95
100
|
|
|
96
101
|
## クイックスタート
|
package/README.md
CHANGED
|
@@ -66,13 +66,13 @@ The built JavaScript file is committed to this repository so users do not need t
|
|
|
66
66
|
The versioned npm package contains the same reviewed build:
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.6.
|
|
69
|
+
pnpm add --save-exact @kubohiroya/turbowarp-asset-cache@0.6.1
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Load `node_modules/@kubohiroya/turbowarp-asset-cache/dist/asset-cache.js`, or use the version-pinned CDN URL:
|
|
73
73
|
|
|
74
74
|
```text
|
|
75
|
-
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.6.
|
|
75
|
+
https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-asset-cache@0.6.1/dist/asset-cache.js
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
## Quick Start
|
package/dist/asset-cache.js
CHANGED
|
@@ -2341,9 +2341,9 @@ function validateProjectAssetAddress(runtime, assetName, resourceIdentifier) {
|
|
|
2341
2341
|
}
|
|
2342
2342
|
}
|
|
2343
2343
|
var AssetManagerExtension = class {
|
|
2344
|
-
constructor(featureFlags = FEATURE_FLAGS) {
|
|
2345
|
-
_defineProperty(this, "runtime",
|
|
2346
|
-
_defineProperty(this, "renderer",
|
|
2344
|
+
constructor(featureFlags = FEATURE_FLAGS, runtime = Scratch.vm.runtime) {
|
|
2345
|
+
_defineProperty(this, "runtime", void 0);
|
|
2346
|
+
_defineProperty(this, "renderer", void 0);
|
|
2347
2347
|
_defineProperty(this, "externalAssets", /* @__PURE__ */ new Map());
|
|
2348
2348
|
_defineProperty(this, "costumeAssets", /* @__PURE__ */ new Map());
|
|
2349
2349
|
_defineProperty(this, "soundAssets", /* @__PURE__ */ new Map());
|
|
@@ -2393,6 +2393,12 @@ var AssetManagerExtension = class {
|
|
|
2393
2393
|
this.unbindNamedDataRegistryLifecycle = void 0;
|
|
2394
2394
|
});
|
|
2395
2395
|
_defineProperty(this, "fixedEditors", fixedInputRegistration(Scratch));
|
|
2396
|
+
_defineProperty(this, "listeningForTargetStops", false);
|
|
2397
|
+
_defineProperty(this, "releaseStoppedTarget", (target) => {
|
|
2398
|
+
if (target && !this.runtime.targets.includes(target)) this.displayedAssets.delete(target.id);
|
|
2399
|
+
});
|
|
2400
|
+
this.runtime = runtime;
|
|
2401
|
+
this.renderer = runtime.renderer;
|
|
2396
2402
|
this.featureFlags = Object.freeze({ ...featureFlags });
|
|
2397
2403
|
if (this.featureFlags.NAMED_ASSET_BODY_PROVIDER) {
|
|
2398
2404
|
this.namedBodyProviderValue = this.createNamedBodyProvider();
|
|
@@ -2401,9 +2407,19 @@ var AssetManagerExtension = class {
|
|
|
2401
2407
|
this.unbindNamedDataRegistryLifecycle = bindNamedDataRegistryLifecycle(this.runtime, registry);
|
|
2402
2408
|
this.startListeningForNamedBodyLifecycle();
|
|
2403
2409
|
}
|
|
2404
|
-
this.
|
|
2405
|
-
|
|
2406
|
-
|
|
2410
|
+
this.ensureRuntimeListeners();
|
|
2411
|
+
}
|
|
2412
|
+
/** A reusable composition reattaches its own listener when registering new assets. */
|
|
2413
|
+
ensureRuntimeListeners() {
|
|
2414
|
+
if (this.listeningForTargetStops || !this.runtime.on) return;
|
|
2415
|
+
this.runtime.on("STOP_FOR_TARGET", this.releaseStoppedTarget);
|
|
2416
|
+
this.listeningForTargetStops = true;
|
|
2417
|
+
}
|
|
2418
|
+
/** Release only this instance's subscription, leaving other runtime owners untouched. */
|
|
2419
|
+
releaseRuntimeListeners() {
|
|
2420
|
+
if (!this.listeningForTargetStops || !this.runtime.off) return;
|
|
2421
|
+
this.runtime.off("STOP_FOR_TARGET", this.releaseStoppedTarget);
|
|
2422
|
+
this.listeningForTargetStops = false;
|
|
2407
2423
|
}
|
|
2408
2424
|
setLoadingBackdrop(args) {
|
|
2409
2425
|
this.loadingBackdropName = normalizeName(args.NAME);
|
package/dist/composition.js
CHANGED
|
@@ -2293,8 +2293,8 @@ function validateProjectAssetAddress(runtime, assetName, resourceIdentifier) {
|
|
|
2293
2293
|
}
|
|
2294
2294
|
}
|
|
2295
2295
|
var AssetManagerExtension = class {
|
|
2296
|
-
runtime
|
|
2297
|
-
renderer
|
|
2296
|
+
runtime;
|
|
2297
|
+
renderer;
|
|
2298
2298
|
externalAssets = /* @__PURE__ */ new Map();
|
|
2299
2299
|
costumeAssets = /* @__PURE__ */ new Map();
|
|
2300
2300
|
soundAssets = /* @__PURE__ */ new Map();
|
|
@@ -2344,7 +2344,13 @@ var AssetManagerExtension = class {
|
|
|
2344
2344
|
this.unbindNamedDataRegistryLifecycle = void 0;
|
|
2345
2345
|
};
|
|
2346
2346
|
fixedEditors = fixedInputRegistration(Scratch);
|
|
2347
|
-
|
|
2347
|
+
listeningForTargetStops = false;
|
|
2348
|
+
releaseStoppedTarget = (target) => {
|
|
2349
|
+
if (target && !this.runtime.targets.includes(target)) this.displayedAssets.delete(target.id);
|
|
2350
|
+
};
|
|
2351
|
+
constructor(featureFlags = FEATURE_FLAGS, runtime = Scratch.vm.runtime) {
|
|
2352
|
+
this.runtime = runtime;
|
|
2353
|
+
this.renderer = runtime.renderer;
|
|
2348
2354
|
this.featureFlags = Object.freeze({ ...featureFlags });
|
|
2349
2355
|
if (this.featureFlags.NAMED_ASSET_BODY_PROVIDER) {
|
|
2350
2356
|
this.namedBodyProviderValue = this.createNamedBodyProvider();
|
|
@@ -2353,9 +2359,19 @@ var AssetManagerExtension = class {
|
|
|
2353
2359
|
this.unbindNamedDataRegistryLifecycle = bindNamedDataRegistryLifecycle(this.runtime, registry);
|
|
2354
2360
|
this.startListeningForNamedBodyLifecycle();
|
|
2355
2361
|
}
|
|
2356
|
-
this.
|
|
2357
|
-
|
|
2358
|
-
|
|
2362
|
+
this.ensureRuntimeListeners();
|
|
2363
|
+
}
|
|
2364
|
+
/** A reusable composition reattaches its own listener when registering new assets. */
|
|
2365
|
+
ensureRuntimeListeners() {
|
|
2366
|
+
if (this.listeningForTargetStops || !this.runtime.on) return;
|
|
2367
|
+
this.runtime.on("STOP_FOR_TARGET", this.releaseStoppedTarget);
|
|
2368
|
+
this.listeningForTargetStops = true;
|
|
2369
|
+
}
|
|
2370
|
+
/** Release only this instance's subscription, leaving other runtime owners untouched. */
|
|
2371
|
+
releaseRuntimeListeners() {
|
|
2372
|
+
if (!this.listeningForTargetStops || !this.runtime.off) return;
|
|
2373
|
+
this.runtime.off("STOP_FOR_TARGET", this.releaseStoppedTarget);
|
|
2374
|
+
this.listeningForTargetStops = false;
|
|
2359
2375
|
}
|
|
2360
2376
|
setLoadingBackdrop(args) {
|
|
2361
2377
|
this.loadingBackdropName = normalizeName(args.NAME);
|
|
@@ -8732,7 +8748,10 @@ async function createSessionBinaryBacking(inputValue, optionValue = {}, operatio
|
|
|
8732
8748
|
//#region src/composition.ts
|
|
8733
8749
|
function createAssetManagerComposition(featureFlags, options = {}) {
|
|
8734
8750
|
if (!options || typeof options !== "object" || Array.isArray(options)) throw new TypeError("Asset Cache composition options must be an object.");
|
|
8735
|
-
const
|
|
8751
|
+
const runtimeInput = options.runtime === void 0 ? Scratch.vm.runtime : options.runtime;
|
|
8752
|
+
if (options.runtime !== void 0 && (!runtimeInput || typeof runtimeInput !== "object" || !Array.isArray(runtimeInput.targets) || !runtimeInput.renderer || typeof runtimeInput.renderer !== "object")) throw new TypeError("Asset Cache composition runtime must provide targets and renderer.");
|
|
8753
|
+
const runtime = runtimeInput;
|
|
8754
|
+
const extension = new AssetManagerExtension(featureFlags, runtime);
|
|
8736
8755
|
const ownedNames = /* @__PURE__ */ new Map();
|
|
8737
8756
|
let literalNameSequence = 0;
|
|
8738
8757
|
let verifiedRemoteCache = null;
|
|
@@ -9012,7 +9031,6 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9012
9031
|
previous?.resource.release();
|
|
9013
9032
|
return resource;
|
|
9014
9033
|
}
|
|
9015
|
-
const runtime = Scratch.vm.runtime;
|
|
9016
9034
|
let listeningForDOMImageLifecycle = false;
|
|
9017
9035
|
const releaseStoppedTargetDOMImageResources = (target) => {
|
|
9018
9036
|
if (target && !runtime.targets.includes(target)) releaseDOMImageResourcesForOwner(target.id);
|
|
@@ -9036,6 +9054,7 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9036
9054
|
return Object.freeze({
|
|
9037
9055
|
async registerProjectAsset(input) {
|
|
9038
9056
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new TypeError("Project asset registration input must be an object.");
|
|
9057
|
+
extension.ensureRuntimeListeners();
|
|
9039
9058
|
const hasLocator = Object.hasOwn(input, "locator");
|
|
9040
9059
|
if (hasLocator === Object.hasOwn(input, "resourceId")) throw new TypeError("Provide exactly one project asset locator or resourceId.");
|
|
9041
9060
|
const claimed = claimName(input.name, input.nameMode ?? (hasLocator ? "literal" : "trimmed"));
|
|
@@ -9045,6 +9064,7 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9045
9064
|
}));
|
|
9046
9065
|
},
|
|
9047
9066
|
async registerEmbeddedAsset(input) {
|
|
9067
|
+
extension.ensureRuntimeListeners();
|
|
9048
9068
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new TypeError("Embedded asset registration input must be an object.");
|
|
9049
9069
|
const claimed = claimName(input.name, input.nameMode ?? "trimmed");
|
|
9050
9070
|
return trackRegistration(claimed, extension.registerEmbeddedAsset({
|
|
@@ -9057,9 +9077,13 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9057
9077
|
},
|
|
9058
9078
|
releaseAsset,
|
|
9059
9079
|
releaseAll() {
|
|
9060
|
-
releaseAllDOMImageResources();
|
|
9061
|
-
audioGeneration++;
|
|
9062
9080
|
const errors = [];
|
|
9081
|
+
try {
|
|
9082
|
+
releaseAllDOMImageResources();
|
|
9083
|
+
} catch (error) {
|
|
9084
|
+
errors.push(error);
|
|
9085
|
+
}
|
|
9086
|
+
audioGeneration++;
|
|
9063
9087
|
for (const playback of audioPlaybacks) try {
|
|
9064
9088
|
playback.dispose();
|
|
9065
9089
|
} catch (error) {
|
|
@@ -9070,6 +9094,11 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9070
9094
|
} catch (error) {
|
|
9071
9095
|
errors.push(error);
|
|
9072
9096
|
}
|
|
9097
|
+
try {
|
|
9098
|
+
extension.releaseRuntimeListeners();
|
|
9099
|
+
} catch (error) {
|
|
9100
|
+
errors.push(error);
|
|
9101
|
+
}
|
|
9073
9102
|
if (errors.length > 0) throw new AggregateError(errors, "Failed to release assets");
|
|
9074
9103
|
},
|
|
9075
9104
|
isRegistered(name) {
|
|
@@ -9101,7 +9130,7 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9101
9130
|
applyToTarget(name, target) {
|
|
9102
9131
|
return extension.setThisSpriteSkin({ NAME: ownedName(name)?.internal ?? name }, {
|
|
9103
9132
|
target,
|
|
9104
|
-
runtime
|
|
9133
|
+
runtime
|
|
9105
9134
|
});
|
|
9106
9135
|
},
|
|
9107
9136
|
playSound(name, options = {}) {
|
|
@@ -9187,5 +9216,7 @@ function createAssetManagerComposition(featureFlags, options = {}) {
|
|
|
9187
9216
|
}
|
|
9188
9217
|
});
|
|
9189
9218
|
}
|
|
9219
|
+
createAssetManagerComposition.supportsRuntimeIsolation = true;
|
|
9220
|
+
Object.defineProperty(createAssetManagerComposition, "supportsRuntimeIsolation", { writable: false });
|
|
9190
9221
|
//#endregion
|
|
9191
9222
|
export { NAMED_ASSET_BODY_NAMESPACE, NamedAssetBodyError, createAssetManagerComposition, createBinaryBundleStore, createIndexedDBBinaryObjectStore, createOpfsBinaryObjectStore, createSessionBinaryBacking, createVerifiedRemoteBinaryCache, createVerifiedRemoteCacheDatabaseName };
|
|
@@ -65,7 +65,20 @@ export interface DOMImageResourceBindingOptions {
|
|
|
65
65
|
readonly attribute?: 'href' | 'src';
|
|
66
66
|
readonly owner?: AssetManagerCompositionTarget;
|
|
67
67
|
}
|
|
68
|
+
/** Public runtime boundary; rendering and asset capabilities are checked when used. */
|
|
69
|
+
export interface AssetManagerCompositionRuntime {
|
|
70
|
+
readonly renderer: object;
|
|
71
|
+
readonly targets: readonly object[];
|
|
72
|
+
readonly storage?: unknown;
|
|
73
|
+
readonly stageWidth?: number;
|
|
74
|
+
on?(eventName: string, listener: (target?: AssetManagerCompositionTarget) => void): unknown;
|
|
75
|
+
off?(eventName: string, listener: (target?: AssetManagerCompositionTarget) => void): unknown;
|
|
76
|
+
requestRedraw?(): unknown;
|
|
77
|
+
getOpcodeFunction?(opcode: string): unknown;
|
|
78
|
+
}
|
|
68
79
|
export interface AssetManagerCompositionOptions {
|
|
80
|
+
/** Explicit owner for independent preview/player runtimes; defaults to the extension host. */
|
|
81
|
+
readonly runtime?: AssetManagerCompositionRuntime;
|
|
69
82
|
readonly verifiedRemoteCache?: VerifiedRemoteBinaryCacheOptions;
|
|
70
83
|
readonly binaryBundleStore?: BinaryBundleStoreOptions;
|
|
71
84
|
readonly sessionBinaryBacking?: SessionBinaryBackingOptions;
|
|
@@ -112,3 +125,6 @@ export interface AssetManagerComposition {
|
|
|
112
125
|
createSessionBinaryBacking(input: SessionBinaryBackingInput, options?: BinaryBundleOperationOptions): Promise<SessionBinaryBacking>;
|
|
113
126
|
}
|
|
114
127
|
export declare function createAssetManagerComposition(featureFlags?: AssetManagerFeatureFlags, options?: AssetManagerCompositionOptions): AssetManagerComposition;
|
|
128
|
+
export declare namespace createAssetManagerComposition {
|
|
129
|
+
var supportsRuntimeIsolation: true;
|
|
130
|
+
}
|
|
@@ -124,7 +124,13 @@ export declare class AssetManagerExtension {
|
|
|
124
124
|
private readonly releaseNamedBodySnapshotsForLifecycle;
|
|
125
125
|
private readonly unregisterNamedBodyProviderForRuntimeDispose;
|
|
126
126
|
private readonly fixedEditors;
|
|
127
|
-
|
|
127
|
+
private listeningForTargetStops;
|
|
128
|
+
private readonly releaseStoppedTarget;
|
|
129
|
+
constructor(featureFlags?: AssetManagerFeatureFlags, runtime?: TurboWarpRuntime);
|
|
130
|
+
/** A reusable composition reattaches its own listener when registering new assets. */
|
|
131
|
+
ensureRuntimeListeners(): void;
|
|
132
|
+
/** Release only this instance's subscription, leaving other runtime owners untouched. */
|
|
133
|
+
releaseRuntimeListeners(): void;
|
|
128
134
|
setLoadingBackdrop(args: BlockArgs): void;
|
|
129
135
|
setLoadingCostumes(args: BlockArgs): void;
|
|
130
136
|
prepareLoadingAssets(args: BlockArgs, util: ScratchBlockUtility): void;
|