@camstack/system 1.1.43 → 1.1.45
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/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +8 -2
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +24 -9
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +24 -9
- package/dist/index.js +21 -2
- package/dist/index.mjs +21 -2
- package/package.json +1 -1
|
@@ -43,8 +43,14 @@ export declare class AddonWidgetsAggregatorAddon extends BaseAddon {
|
|
|
43
43
|
* just gets a fresh URL on each call instead of cache-friendly mtime.
|
|
44
44
|
*/
|
|
45
45
|
private makeBundleUrl;
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* sha1 (12-hex) over EVERY file in the bundle's dist dir — content, not
|
|
48
|
+
* mtime (reproducible builds fix mtime, so mtime never busts). Memoised by
|
|
49
|
+
* the dir's (name:size:mtime) fingerprint; a redeploy that changes any
|
|
50
|
+
* file's content changes its size and re-hashes. `Date.now()` when the
|
|
51
|
+
* bundle has no local file (remote addon).
|
|
52
|
+
*/
|
|
53
|
+
private bundleDirVersionTag;
|
|
48
54
|
private resolveBundlePath;
|
|
49
55
|
private resolvePaths;
|
|
50
56
|
}
|
|
@@ -198,19 +198,34 @@ var AddonWidgetsAggregatorAddon = class extends require_dist.BaseAddon {
|
|
|
198
198
|
*/
|
|
199
199
|
makeBundleUrl(addonId, bundle) {
|
|
200
200
|
const bundlePath = this.resolveBundlePath(addonId, bundle);
|
|
201
|
-
return `/api/addon-widgets/${addonId}
|
|
201
|
+
return `/api/addon-widgets/${addonId}/v${this.bundleDirVersionTag(bundlePath)}/${bundle}`;
|
|
202
202
|
}
|
|
203
|
-
/**
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
/**
|
|
204
|
+
* sha1 (12-hex) over EVERY file in the bundle's dist dir — content, not
|
|
205
|
+
* mtime (reproducible builds fix mtime, so mtime never busts). Memoised by
|
|
206
|
+
* the dir's (name:size:mtime) fingerprint; a redeploy that changes any
|
|
207
|
+
* file's content changes its size and re-hashes. `Date.now()` when the
|
|
208
|
+
* bundle has no local file (remote addon).
|
|
209
|
+
*/
|
|
210
|
+
bundleDirVersionTag(entryPath) {
|
|
211
|
+
if (entryPath === null) return String(Math.floor(Date.now()));
|
|
206
212
|
try {
|
|
207
|
-
const
|
|
208
|
-
const
|
|
213
|
+
const dir = node_path.dirname(entryPath);
|
|
214
|
+
const files = node_fs.readdirSync(dir).filter((f) => node_fs.statSync(node_path.join(dir, f)).isFile()).sort();
|
|
215
|
+
const cacheKey = `${dir}#${files.map((f) => {
|
|
216
|
+
const s = node_fs.statSync(node_path.join(dir, f));
|
|
217
|
+
return `${f}:${s.size}:${s.mtimeMs}`;
|
|
218
|
+
}).join("|")}`;
|
|
209
219
|
const cached = this.bundleHashCache.get(cacheKey);
|
|
210
220
|
if (cached !== void 0) return cached;
|
|
211
|
-
const hash = (0, node_crypto.createHash)("sha1")
|
|
212
|
-
|
|
213
|
-
|
|
221
|
+
const hash = (0, node_crypto.createHash)("sha1");
|
|
222
|
+
for (const f of files) {
|
|
223
|
+
hash.update(f);
|
|
224
|
+
hash.update(node_fs.readFileSync(node_path.join(dir, f)));
|
|
225
|
+
}
|
|
226
|
+
const digest = hash.digest("hex").slice(0, 12);
|
|
227
|
+
this.bundleHashCache.set(cacheKey, digest);
|
|
228
|
+
return digest;
|
|
214
229
|
} catch {
|
|
215
230
|
return String(Math.floor(Date.now()));
|
|
216
231
|
}
|
|
@@ -191,19 +191,34 @@ var AddonWidgetsAggregatorAddon = class extends BaseAddon {
|
|
|
191
191
|
*/
|
|
192
192
|
makeBundleUrl(addonId, bundle) {
|
|
193
193
|
const bundlePath = this.resolveBundlePath(addonId, bundle);
|
|
194
|
-
return `/api/addon-widgets/${addonId}
|
|
194
|
+
return `/api/addon-widgets/${addonId}/v${this.bundleDirVersionTag(bundlePath)}/${bundle}`;
|
|
195
195
|
}
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
/**
|
|
197
|
+
* sha1 (12-hex) over EVERY file in the bundle's dist dir — content, not
|
|
198
|
+
* mtime (reproducible builds fix mtime, so mtime never busts). Memoised by
|
|
199
|
+
* the dir's (name:size:mtime) fingerprint; a redeploy that changes any
|
|
200
|
+
* file's content changes its size and re-hashes. `Date.now()` when the
|
|
201
|
+
* bundle has no local file (remote addon).
|
|
202
|
+
*/
|
|
203
|
+
bundleDirVersionTag(entryPath) {
|
|
204
|
+
if (entryPath === null) return String(Math.floor(Date.now()));
|
|
199
205
|
try {
|
|
200
|
-
const
|
|
201
|
-
const
|
|
206
|
+
const dir = path$1.dirname(entryPath);
|
|
207
|
+
const files = fs.readdirSync(dir).filter((f) => fs.statSync(path$1.join(dir, f)).isFile()).sort();
|
|
208
|
+
const cacheKey = `${dir}#${files.map((f) => {
|
|
209
|
+
const s = fs.statSync(path$1.join(dir, f));
|
|
210
|
+
return `${f}:${s.size}:${s.mtimeMs}`;
|
|
211
|
+
}).join("|")}`;
|
|
202
212
|
const cached = this.bundleHashCache.get(cacheKey);
|
|
203
213
|
if (cached !== void 0) return cached;
|
|
204
|
-
const hash = createHash("sha1")
|
|
205
|
-
|
|
206
|
-
|
|
214
|
+
const hash = createHash("sha1");
|
|
215
|
+
for (const f of files) {
|
|
216
|
+
hash.update(f);
|
|
217
|
+
hash.update(fs.readFileSync(path$1.join(dir, f)));
|
|
218
|
+
}
|
|
219
|
+
const digest = hash.digest("hex").slice(0, 12);
|
|
220
|
+
this.bundleHashCache.set(cacheKey, digest);
|
|
221
|
+
return digest;
|
|
207
222
|
} catch {
|
|
208
223
|
return String(Math.floor(Date.now()));
|
|
209
224
|
}
|
package/dist/index.js
CHANGED
|
@@ -5007,6 +5007,23 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5007
5007
|
* `buildCapRouters(t, services)` contract), keeping the kernel free of any
|
|
5008
5008
|
* backend coupling (self-sufficiency invariant).
|
|
5009
5009
|
*/
|
|
5010
|
+
/**
|
|
5011
|
+
* The mount kind a `systemOnly` method resolves through — the cap's
|
|
5012
|
+
* SYSTEM/wrapper provider, keyed off the cap's `mode` (singleton or
|
|
5013
|
+
* collection), NEVER the per-device native.
|
|
5014
|
+
*
|
|
5015
|
+
* A `systemOnly` method (declared via the `systemMethod()` factory) belongs
|
|
5016
|
+
* to the cap's hub-resident system/wrapper provider — e.g. a device-scoped
|
|
5017
|
+
* (`device-native`) cap exposing a batch/metadata call that takes `deviceIds`
|
|
5018
|
+
* (an ARRAY) rather than a single `deviceId`. Routing it through the cap's
|
|
5019
|
+
* `device-native` mount would push it into `requireDeviceScoped`, whose
|
|
5020
|
+
* dispatcher demands a numeric `deviceId` on EVERY method call and rejects a
|
|
5021
|
+
* deviceId-less input with `input must carry numeric "deviceId"`. Resolving it
|
|
5022
|
+
* as the cap's mode-appropriate system provider instead keeps it reachable.
|
|
5023
|
+
*/
|
|
5024
|
+
function systemMountKindFor(def) {
|
|
5025
|
+
return def.mode === "collection" ? "collection" : "singleton";
|
|
5026
|
+
}
|
|
5010
5027
|
function methodsFor(def) {
|
|
5011
5028
|
const effective = require_dist.expandCapMethods(def);
|
|
5012
5029
|
return Object.entries(effective).map(([name, schema]) => {
|
|
@@ -5065,11 +5082,13 @@ function requireLocal(capName, getLocal, services) {
|
|
|
5065
5082
|
function buildOneCapRouter(def, primitives, services) {
|
|
5066
5083
|
const capName = def.name;
|
|
5067
5084
|
const mount = require_dist.resolveCapMount(def);
|
|
5068
|
-
const
|
|
5085
|
+
const systemMountKind = systemMountKindFor(def);
|
|
5069
5086
|
const nodeIdData = def.nodeIdMode === "data";
|
|
5070
5087
|
const procedures = {};
|
|
5071
|
-
const getLocal = (ctx, addonId) => services.getLocalProvider(capName, mount.kind, ctx, addonId);
|
|
5072
5088
|
for (const method of methodsFor(def)) {
|
|
5089
|
+
const effectiveMountKind = method.schema.systemOnly === true ? systemMountKind : mount.kind;
|
|
5090
|
+
const isCollection = effectiveMountKind === "collection";
|
|
5091
|
+
const getLocal = (ctx, addonId) => services.getLocalProvider(capName, effectiveMountKind, ctx, addonId);
|
|
5073
5092
|
const base = primitives.procedures[require_dist.procedureAuthKey(method.auth)];
|
|
5074
5093
|
const inputSchema = method.schema.input;
|
|
5075
5094
|
if (method.kind === "subscription") {
|
package/dist/index.mjs
CHANGED
|
@@ -4999,6 +4999,23 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
4999
4999
|
* `buildCapRouters(t, services)` contract), keeping the kernel free of any
|
|
5000
5000
|
* backend coupling (self-sufficiency invariant).
|
|
5001
5001
|
*/
|
|
5002
|
+
/**
|
|
5003
|
+
* The mount kind a `systemOnly` method resolves through — the cap's
|
|
5004
|
+
* SYSTEM/wrapper provider, keyed off the cap's `mode` (singleton or
|
|
5005
|
+
* collection), NEVER the per-device native.
|
|
5006
|
+
*
|
|
5007
|
+
* A `systemOnly` method (declared via the `systemMethod()` factory) belongs
|
|
5008
|
+
* to the cap's hub-resident system/wrapper provider — e.g. a device-scoped
|
|
5009
|
+
* (`device-native`) cap exposing a batch/metadata call that takes `deviceIds`
|
|
5010
|
+
* (an ARRAY) rather than a single `deviceId`. Routing it through the cap's
|
|
5011
|
+
* `device-native` mount would push it into `requireDeviceScoped`, whose
|
|
5012
|
+
* dispatcher demands a numeric `deviceId` on EVERY method call and rejects a
|
|
5013
|
+
* deviceId-less input with `input must carry numeric "deviceId"`. Resolving it
|
|
5014
|
+
* as the cap's mode-appropriate system provider instead keeps it reachable.
|
|
5015
|
+
*/
|
|
5016
|
+
function systemMountKindFor(def) {
|
|
5017
|
+
return def.mode === "collection" ? "collection" : "singleton";
|
|
5018
|
+
}
|
|
5002
5019
|
function methodsFor(def) {
|
|
5003
5020
|
const effective = expandCapMethods(def);
|
|
5004
5021
|
return Object.entries(effective).map(([name, schema]) => {
|
|
@@ -5057,11 +5074,13 @@ function requireLocal(capName, getLocal, services) {
|
|
|
5057
5074
|
function buildOneCapRouter(def, primitives, services) {
|
|
5058
5075
|
const capName = def.name;
|
|
5059
5076
|
const mount = resolveCapMount(def);
|
|
5060
|
-
const
|
|
5077
|
+
const systemMountKind = systemMountKindFor(def);
|
|
5061
5078
|
const nodeIdData = def.nodeIdMode === "data";
|
|
5062
5079
|
const procedures = {};
|
|
5063
|
-
const getLocal = (ctx, addonId) => services.getLocalProvider(capName, mount.kind, ctx, addonId);
|
|
5064
5080
|
for (const method of methodsFor(def)) {
|
|
5081
|
+
const effectiveMountKind = method.schema.systemOnly === true ? systemMountKind : mount.kind;
|
|
5082
|
+
const isCollection = effectiveMountKind === "collection";
|
|
5083
|
+
const getLocal = (ctx, addonId) => services.getLocalProvider(capName, effectiveMountKind, ctx, addonId);
|
|
5065
5084
|
const base = primitives.procedures[procedureAuthKey(method.auth)];
|
|
5066
5085
|
const inputSchema = method.schema.input;
|
|
5067
5086
|
if (method.kind === "subscription") {
|