@hoardodile/host 0.1.2 → 0.1.3
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/chunks/worker-entry.mjs +6 -1
- package/dist/hoard/index.d.ts +24 -19
- package/dist/hoard/index.js +22 -4
- package/dist/hoard/index.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +77 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/hoard/index.ts +4 -1
- package/src/hoard/paths.ts +37 -11
- package/src/hoard/versioned-folder-ops.ts +29 -6
- package/src/hooks.test.ts +70 -0
- package/src/hooks.ts +26 -0
- package/src/install-api.ts +68 -0
- package/src/sandbox/host.ts +30 -1
- package/src/sandbox/worker-entry.mjs +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -685,6 +685,18 @@ type PluginHooks = {
|
|
|
685
685
|
* shape-validated (hex values, per-resource cap).
|
|
686
686
|
*/
|
|
687
687
|
readonly runImageHashes: (api: ResourceAPI, pluginId: PluginManifestId) => Promise<ImageHashesResult | undefined>;
|
|
688
|
+
/**
|
|
689
|
+
* Run the plugin's optional `onInstall` hook — best-effort, invoked
|
|
690
|
+
* by the host after a successful install/update commit (marketplace
|
|
691
|
+
* install/update or a zip upload; never seed/dev plugins). The hook
|
|
692
|
+
* receives an install-scoped {@link ResourceAPI}: no resource is
|
|
693
|
+
* attached (the file surface answers empty, `context.detect` is
|
|
694
|
+
* `undefined`), while the asset methods still work and stay gated by
|
|
695
|
+
* the shared consent dialog. A throwing (or consent-denied) hook is
|
|
696
|
+
* logged via `hookFailureText` and swallowed — the install itself is
|
|
697
|
+
* never failed; plugins must re-check at runtime.
|
|
698
|
+
*/
|
|
699
|
+
readonly runInstallHook: (pluginId: PluginManifestId) => Promise<void>;
|
|
688
700
|
};
|
|
689
701
|
declare function createPluginHooks(deps: PluginHooksDeps): PluginHooks;
|
|
690
702
|
|
package/dist/index.js
CHANGED
|
@@ -2298,6 +2298,59 @@ function parseManifest(dirPath, dirName) {
|
|
|
2298
2298
|
}
|
|
2299
2299
|
return result.data;
|
|
2300
2300
|
}
|
|
2301
|
+
function createInstallScopeApi() {
|
|
2302
|
+
const noResource = (method) => new Error(
|
|
2303
|
+
`${method}() \u2014 no resource is attached to the onInstall hook; use the asset methods (download/statAsset/readAsset/deleteAsset) for install-time work`
|
|
2304
|
+
);
|
|
2305
|
+
return {
|
|
2306
|
+
logInfo() {
|
|
2307
|
+
},
|
|
2308
|
+
logWarn() {
|
|
2309
|
+
},
|
|
2310
|
+
logError() {
|
|
2311
|
+
},
|
|
2312
|
+
context: { detect: void 0 },
|
|
2313
|
+
listFileNames: async () => [],
|
|
2314
|
+
readFile: async () => {
|
|
2315
|
+
throw noResource("readFile");
|
|
2316
|
+
},
|
|
2317
|
+
statFile: async () => void 0,
|
|
2318
|
+
statFiles: async (paths) => paths.map(() => void 0),
|
|
2319
|
+
sniff: async () => void 0,
|
|
2320
|
+
probe: async () => ({ kind: "unknown", reason: "unavailable" }),
|
|
2321
|
+
hashBytes: async () => {
|
|
2322
|
+
throw noResource("hashBytes");
|
|
2323
|
+
},
|
|
2324
|
+
computeImageHashes: async () => void 0,
|
|
2325
|
+
listContainer: async () => {
|
|
2326
|
+
throw noResource("listContainer");
|
|
2327
|
+
},
|
|
2328
|
+
extractArchive: async () => {
|
|
2329
|
+
throw noResource("extractArchive");
|
|
2330
|
+
},
|
|
2331
|
+
download: async () => {
|
|
2332
|
+
throw pluginAssetError(
|
|
2333
|
+
"UNAVAILABLE",
|
|
2334
|
+
"download() \u2014 this host has no plugin asset service; only the app server host can download into the plugin vault"
|
|
2335
|
+
);
|
|
2336
|
+
},
|
|
2337
|
+
statAsset: async () => {
|
|
2338
|
+
throw unavailableAsset2("statAsset");
|
|
2339
|
+
},
|
|
2340
|
+
readAsset: async () => {
|
|
2341
|
+
throw unavailableAsset2("readAsset");
|
|
2342
|
+
},
|
|
2343
|
+
deleteAsset: async () => {
|
|
2344
|
+
throw unavailableAsset2("deleteAsset");
|
|
2345
|
+
}
|
|
2346
|
+
};
|
|
2347
|
+
}
|
|
2348
|
+
function unavailableAsset2(method) {
|
|
2349
|
+
return pluginAssetError(
|
|
2350
|
+
"UNAVAILABLE",
|
|
2351
|
+
`${method}() \u2014 this host has no plugin asset vault; only the app server host manages vault files`
|
|
2352
|
+
);
|
|
2353
|
+
}
|
|
2301
2354
|
|
|
2302
2355
|
// src/hooks.ts
|
|
2303
2356
|
var MAX_IMAGE_HASHES_PER_RESOURCE = 2e3;
|
|
@@ -2472,6 +2525,17 @@ function createPluginHooks(deps) {
|
|
|
2472
2525
|
pluginId
|
|
2473
2526
|
);
|
|
2474
2527
|
}
|
|
2528
|
+
async function runInstallHook(pluginId) {
|
|
2529
|
+
const entry = getRegistry().getById(pluginId);
|
|
2530
|
+
if (entry === void 0) return;
|
|
2531
|
+
await invokeHook(
|
|
2532
|
+
entry,
|
|
2533
|
+
entry.plugin.onInstall,
|
|
2534
|
+
createInstallScopeApi(),
|
|
2535
|
+
"onInstall",
|
|
2536
|
+
"warn"
|
|
2537
|
+
);
|
|
2538
|
+
}
|
|
2475
2539
|
return {
|
|
2476
2540
|
defaultPluginId,
|
|
2477
2541
|
getEffectiveEntry,
|
|
@@ -2483,7 +2547,8 @@ function createPluginHooks(deps) {
|
|
|
2483
2547
|
resolveLocalCoverSource,
|
|
2484
2548
|
runMetaHooks,
|
|
2485
2549
|
supportsImageHashes,
|
|
2486
|
-
runImageHashes
|
|
2550
|
+
runImageHashes,
|
|
2551
|
+
runInstallHook
|
|
2487
2552
|
};
|
|
2488
2553
|
}
|
|
2489
2554
|
var HEX_VALUE = /^[0-9a-f]+$/;
|
|
@@ -2692,7 +2757,7 @@ function createPluginSandbox(config = DEFAULT_SANDBOX_CONFIG) {
|
|
|
2692
2757
|
await teardownChild(previous);
|
|
2693
2758
|
}
|
|
2694
2759
|
if (!opts.eager) {
|
|
2695
|
-
|
|
2760
|
+
await teardownChild(state);
|
|
2696
2761
|
}
|
|
2697
2762
|
return createSandboxedPlugin(
|
|
2698
2763
|
state.hooks ?? ["detect"],
|
|
@@ -2876,6 +2941,16 @@ function createPluginSandbox(config = DEFAULT_SANDBOX_CONFIG) {
|
|
|
2876
2941
|
if (child === void 0) {
|
|
2877
2942
|
throw new Error(`plugin ${state.id} sandbox unavailable`);
|
|
2878
2943
|
}
|
|
2944
|
+
try {
|
|
2945
|
+
return await invokeOnChild(state, child, hook, api);
|
|
2946
|
+
} finally {
|
|
2947
|
+
if (hook === "onInstall") {
|
|
2948
|
+
state.respawnTimes = [];
|
|
2949
|
+
await teardownChild(state);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
function invokeOnChild(state, child, hook, api) {
|
|
2879
2954
|
const callId = nextCallId++;
|
|
2880
2955
|
return new Promise((resolveCall, reject) => {
|
|
2881
2956
|
const call = {
|