@camstack/system 1.2.109 → 1.2.111
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/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-Ctfhlrtl.js → dist-CQkr5Kw0.js} +31 -51
- package/dist/{dist-_oC_QkQA.mjs → dist-CW4Cims4.mjs} +31 -51
- package/dist/index.js +87 -9
- package/dist/index.mjs +87 -9
- package/dist/kernel/capability-registry.d.ts +51 -3
- package/dist/kernel/host-externals.d.ts +1 -1
- package/dist/kernel/index.d.ts +1 -1
- package/dist/kernel/lifecycle/staging-area.d.ts +1 -0
- package/dist/kernel/transport/child-cap-protocol.d.ts +12 -0
- package/dist/kernel/transport/local-child-registry.d.ts +9 -2
- package/dist/{manifest-python-deps-5ei2xVUh.mjs → manifest-python-deps-Cb1ANt3i.mjs} +35 -8
- package/dist/{manifest-python-deps-GejnH--L.js → manifest-python-deps-MA_BZGBz.js} +35 -8
- package/dist/{retired-settings-keys-pNmoHPTg.js → retired-settings-keys-DCESas5O.js} +1 -1
- package/dist/{retired-settings-keys-Bsjf7HQ-.mjs → retired-settings-keys-DGgOxOir.mjs} +1 -1
- package/package.json +1 -1
|
@@ -11653,128 +11653,103 @@ var COCO_TO_MACRO = {
|
|
|
11653
11653
|
var AUDIO_MACRO_LABELS = [
|
|
11654
11654
|
{
|
|
11655
11655
|
id: "speech",
|
|
11656
|
-
name: "Speech"
|
|
11657
|
-
icon: "🗣️"
|
|
11656
|
+
name: "Speech"
|
|
11658
11657
|
},
|
|
11659
11658
|
{
|
|
11660
11659
|
id: "scream",
|
|
11661
|
-
name: "Scream / Shout"
|
|
11662
|
-
icon: "😱"
|
|
11660
|
+
name: "Scream / Shout"
|
|
11663
11661
|
},
|
|
11664
11662
|
{
|
|
11665
11663
|
id: "crying",
|
|
11666
|
-
name: "Crying / Baby"
|
|
11667
|
-
icon: "😢"
|
|
11664
|
+
name: "Crying / Baby"
|
|
11668
11665
|
},
|
|
11669
11666
|
{
|
|
11670
11667
|
id: "laughter",
|
|
11671
|
-
name: "Laughter"
|
|
11672
|
-
icon: "😂"
|
|
11668
|
+
name: "Laughter"
|
|
11673
11669
|
},
|
|
11674
11670
|
{
|
|
11675
11671
|
id: "music",
|
|
11676
|
-
name: "Music"
|
|
11677
|
-
icon: "🎵"
|
|
11672
|
+
name: "Music"
|
|
11678
11673
|
},
|
|
11679
11674
|
{
|
|
11680
11675
|
id: "dog",
|
|
11681
|
-
name: "Dog"
|
|
11682
|
-
icon: "🐕"
|
|
11676
|
+
name: "Dog"
|
|
11683
11677
|
},
|
|
11684
11678
|
{
|
|
11685
11679
|
id: "cat",
|
|
11686
|
-
name: "Cat"
|
|
11687
|
-
icon: "🐈"
|
|
11680
|
+
name: "Cat"
|
|
11688
11681
|
},
|
|
11689
11682
|
{
|
|
11690
11683
|
id: "bird",
|
|
11691
|
-
name: "Bird"
|
|
11692
|
-
icon: "🐦"
|
|
11684
|
+
name: "Bird"
|
|
11693
11685
|
},
|
|
11694
11686
|
{
|
|
11695
11687
|
id: "animal",
|
|
11696
|
-
name: "Animal (other)"
|
|
11697
|
-
icon: "🐾"
|
|
11688
|
+
name: "Animal (other)"
|
|
11698
11689
|
},
|
|
11699
11690
|
{
|
|
11700
11691
|
id: "alarm",
|
|
11701
|
-
name: "Alarm / Siren"
|
|
11702
|
-
icon: "🚨"
|
|
11692
|
+
name: "Alarm / Siren"
|
|
11703
11693
|
},
|
|
11704
11694
|
{
|
|
11705
11695
|
id: "doorbell",
|
|
11706
|
-
name: "Doorbell / Knock"
|
|
11707
|
-
icon: "🔔"
|
|
11696
|
+
name: "Doorbell / Knock"
|
|
11708
11697
|
},
|
|
11709
11698
|
{
|
|
11710
11699
|
id: "glass_breaking",
|
|
11711
|
-
name: "Glass Breaking"
|
|
11712
|
-
icon: "💥"
|
|
11700
|
+
name: "Glass Breaking"
|
|
11713
11701
|
},
|
|
11714
11702
|
{
|
|
11715
11703
|
id: "gunshot",
|
|
11716
|
-
name: "Gunshot / Explosion"
|
|
11717
|
-
icon: "💣"
|
|
11704
|
+
name: "Gunshot / Explosion"
|
|
11718
11705
|
},
|
|
11719
11706
|
{
|
|
11720
11707
|
id: "vehicle",
|
|
11721
|
-
name: "Vehicle"
|
|
11722
|
-
icon: "🚗"
|
|
11708
|
+
name: "Vehicle"
|
|
11723
11709
|
},
|
|
11724
11710
|
{
|
|
11725
11711
|
id: "siren",
|
|
11726
|
-
name: "Emergency Siren"
|
|
11727
|
-
icon: "🚑"
|
|
11712
|
+
name: "Emergency Siren"
|
|
11728
11713
|
},
|
|
11729
11714
|
{
|
|
11730
11715
|
id: "fire",
|
|
11731
|
-
name: "Fire / Smoke"
|
|
11732
|
-
icon: "🔥"
|
|
11716
|
+
name: "Fire / Smoke"
|
|
11733
11717
|
},
|
|
11734
11718
|
{
|
|
11735
11719
|
id: "water",
|
|
11736
|
-
name: "Water"
|
|
11737
|
-
icon: "💧"
|
|
11720
|
+
name: "Water"
|
|
11738
11721
|
},
|
|
11739
11722
|
{
|
|
11740
11723
|
id: "wind",
|
|
11741
|
-
name: "Wind / Weather"
|
|
11742
|
-
icon: "🌬️"
|
|
11724
|
+
name: "Wind / Weather"
|
|
11743
11725
|
},
|
|
11744
11726
|
{
|
|
11745
11727
|
id: "door",
|
|
11746
|
-
name: "Door"
|
|
11747
|
-
icon: "🚪"
|
|
11728
|
+
name: "Door"
|
|
11748
11729
|
},
|
|
11749
11730
|
{
|
|
11750
11731
|
id: "footsteps",
|
|
11751
|
-
name: "Footsteps"
|
|
11752
|
-
icon: "👣"
|
|
11732
|
+
name: "Footsteps"
|
|
11753
11733
|
},
|
|
11754
11734
|
{
|
|
11755
11735
|
id: "crowd",
|
|
11756
|
-
name: "Crowd / Chatter"
|
|
11757
|
-
icon: "👥"
|
|
11736
|
+
name: "Crowd / Chatter"
|
|
11758
11737
|
},
|
|
11759
11738
|
{
|
|
11760
11739
|
id: "telephone",
|
|
11761
|
-
name: "Telephone"
|
|
11762
|
-
icon: "📞"
|
|
11740
|
+
name: "Telephone"
|
|
11763
11741
|
},
|
|
11764
11742
|
{
|
|
11765
11743
|
id: "engine",
|
|
11766
|
-
name: "Engine / Motor"
|
|
11767
|
-
icon: "⚙️"
|
|
11744
|
+
name: "Engine / Motor"
|
|
11768
11745
|
},
|
|
11769
11746
|
{
|
|
11770
11747
|
id: "tools",
|
|
11771
|
-
name: "Tools / Construction"
|
|
11772
|
-
icon: "🔨"
|
|
11748
|
+
name: "Tools / Construction"
|
|
11773
11749
|
},
|
|
11774
11750
|
{
|
|
11775
11751
|
id: "silence",
|
|
11776
|
-
name: "Silence"
|
|
11777
|
-
icon: "🤫"
|
|
11752
|
+
name: "Silence"
|
|
11778
11753
|
}
|
|
11779
11754
|
];
|
|
11780
11755
|
var YAMNET_TO_MACRO = {
|
|
@@ -16634,6 +16609,12 @@ var DetailResultSchema = z.object({
|
|
|
16634
16609
|
/** FRAME-space bbox (already mapped back from crop space). */
|
|
16635
16610
|
bbox: NativeCropBboxSchema.optional(),
|
|
16636
16611
|
embedding: z.string().optional(),
|
|
16612
|
+
/**
|
|
16613
|
+
* L2 magnitude of the RAW pre-normalization embedding. Additive and optional
|
|
16614
|
+
* so an older runner that does not send it degrades to "unmeasurable", which
|
|
16615
|
+
* the consuming gate treats as accept — never as reject.
|
|
16616
|
+
*/
|
|
16617
|
+
embeddingMagnitude: z.number().optional(),
|
|
16637
16618
|
label: z.string().optional(),
|
|
16638
16619
|
/**
|
|
16639
16620
|
* The tier `label` occupies, copied VERBATIM from the producing step's
|
|
@@ -37784,7 +37765,6 @@ var NC_AUDIO_DEFAULTS = {
|
|
|
37784
37765
|
hitPercent: 60,
|
|
37785
37766
|
samplingSeconds: 10
|
|
37786
37767
|
};
|
|
37787
|
-
new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
|
|
37788
37768
|
new Set(["devices", "classes"]);
|
|
37789
37769
|
NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
|
|
37790
37770
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("./dist-
|
|
3
|
+
const require_dist = require("./dist-CQkr5Kw0.js");
|
|
4
4
|
const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
|
|
5
5
|
require("./builtins/alerts/index.js");
|
|
6
6
|
const require_formatter = require("./formatter-DqAKDlvN.js");
|
|
@@ -25,7 +25,7 @@ const require_builtins_system_config_system_config_addon = require("./builtins/s
|
|
|
25
25
|
require("./builtins/system-config/index.js");
|
|
26
26
|
const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
|
|
27
27
|
const require_file_data_plane = require("./file-data-plane-DUHPHa-Y.js");
|
|
28
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
28
|
+
const require_manifest_python_deps = require("./manifest-python-deps-MA_BZGBz.js");
|
|
29
29
|
const require_resource_monitor = require("./resource-monitor-CdnzxBLP.js");
|
|
30
30
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
31
31
|
let zod = require("zod");
|
|
@@ -5367,6 +5367,7 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5367
5367
|
const state = {
|
|
5368
5368
|
definition,
|
|
5369
5369
|
providers: /* @__PURE__ */ new Map(),
|
|
5370
|
+
providerOwners: /* @__PURE__ */ new Map(),
|
|
5370
5371
|
activeAddonId: null,
|
|
5371
5372
|
router: null,
|
|
5372
5373
|
disabledProviders: /* @__PURE__ */ new Set()
|
|
@@ -5424,8 +5425,15 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5424
5425
|
* Double-register of the same pair is always a programmer error —
|
|
5425
5426
|
* two legitimately different addons implementing the same cap keep
|
|
5426
5427
|
* using different `addonId`s and the user picks one via `configReader`.
|
|
5427
|
-
|
|
5428
|
-
|
|
5428
|
+
*
|
|
5429
|
+
* `owner` (optional) stamps the registration with the incarnation that made
|
|
5430
|
+
* it — see {@link ProviderOwnerToken}. Once stamped, only an unregister
|
|
5431
|
+
* presenting the SAME token can delete it. Registration paths whose key is
|
|
5432
|
+
* reused across process generations (the UDS child manifest, the D3
|
|
5433
|
+
* `registerNode` handshake) MUST pass one; ownerless registrations keep the
|
|
5434
|
+
* historical unconditional behaviour.
|
|
5435
|
+
*/
|
|
5436
|
+
registerProvider(capabilityName, addonId, provider, owner) {
|
|
5429
5437
|
let state = this.capabilities.get(capabilityName);
|
|
5430
5438
|
if (!state) {
|
|
5431
5439
|
const colonIdx = capabilityName.indexOf(":");
|
|
@@ -5457,6 +5465,7 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5457
5465
|
if (missing.length > 0) throw new Error(`CapabilityRegistry: provider "${addonId}" for capability "${capabilityName}" declares exposesDeviceSettings: true but is missing DeviceSettingsContribution method(s): ${missing.join(", ")}. Implement them on the provider (or drop the flag from the cap def).`);
|
|
5458
5466
|
}
|
|
5459
5467
|
state.providers.set(addonId, provider);
|
|
5468
|
+
if (owner !== void 0) state.providerOwners.set(addonId, owner);
|
|
5460
5469
|
if (state.definition.mode === "singleton") {
|
|
5461
5470
|
const userChoice = this.configReader?.(capabilityName);
|
|
5462
5471
|
const preferred = state.definition.preferredProvider;
|
|
@@ -5487,7 +5496,8 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5487
5496
|
tags: { addonId },
|
|
5488
5497
|
meta: {
|
|
5489
5498
|
capability: capabilityName,
|
|
5490
|
-
mode: state.definition.mode
|
|
5499
|
+
mode: state.definition.mode,
|
|
5500
|
+
...owner === void 0 ? {} : { owner }
|
|
5491
5501
|
}
|
|
5492
5502
|
});
|
|
5493
5503
|
this.emitEvent("capability:provider-registered", {
|
|
@@ -5534,11 +5544,70 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5534
5544
|
const declarers = this.manifestDeclarers.get(capabilityName);
|
|
5535
5545
|
return declarers ? [...declarers] : [];
|
|
5536
5546
|
}
|
|
5537
|
-
/**
|
|
5538
|
-
|
|
5547
|
+
/**
|
|
5548
|
+
* The owner token a registration declared, or `null` when the pair is not
|
|
5549
|
+
* registered or was registered without one.
|
|
5550
|
+
*/
|
|
5551
|
+
getProviderOwner(capabilityName, addonId) {
|
|
5552
|
+
return this.capabilities.get(capabilityName)?.providerOwners.get(addonId) ?? null;
|
|
5553
|
+
}
|
|
5554
|
+
/**
|
|
5555
|
+
* Hand an EXISTING registration to a new owner, without touching the provider
|
|
5556
|
+
* instance, the active-singleton selection or any event.
|
|
5557
|
+
*
|
|
5558
|
+
* The takeover case: a replacement runner handshakes with an UNCHANGED cap
|
|
5559
|
+
* set, so the manifest diff correctly leaves the registration alone — but the
|
|
5560
|
+
* registration is still stamped with the dead generation's token, and nothing
|
|
5561
|
+
* the LIVE generation can present would ever match it. Re-stamping keeps the
|
|
5562
|
+
* capability cleanable when the successor eventually dies.
|
|
5563
|
+
*
|
|
5564
|
+
* Returns `false` when the pair is not registered (nothing to hand over) —
|
|
5565
|
+
* the caller decides whether that is a register-instead or a diagnosis.
|
|
5566
|
+
*/
|
|
5567
|
+
reassignProviderOwner(capabilityName, addonId, owner) {
|
|
5568
|
+
const state = this.capabilities.get(capabilityName);
|
|
5569
|
+
if (!state || !state.providers.has(addonId)) return false;
|
|
5570
|
+
const previous = state.providerOwners.get(addonId);
|
|
5571
|
+
if (previous === owner) return true;
|
|
5572
|
+
state.providerOwners.set(addonId, owner);
|
|
5573
|
+
this.logger.info("Capability registration ownership reassigned", {
|
|
5574
|
+
tags: { addonId },
|
|
5575
|
+
meta: {
|
|
5576
|
+
capability: capabilityName,
|
|
5577
|
+
owner,
|
|
5578
|
+
previousOwner: previous ?? null
|
|
5579
|
+
}
|
|
5580
|
+
});
|
|
5581
|
+
return true;
|
|
5582
|
+
}
|
|
5583
|
+
/**
|
|
5584
|
+
* Unregister a provider. For singleton: clears active. For collection:
|
|
5585
|
+
* removes from list.
|
|
5586
|
+
*
|
|
5587
|
+
* `owner` is the caller's PROOF that it owns the registration it is deleting.
|
|
5588
|
+
* When the registration declared an owner (see {@link ProviderOwnerToken})
|
|
5589
|
+
* and the caller presents a different one — or none at all — this is a
|
|
5590
|
+
* logged no-op: the caller belongs to a generation that no longer holds the
|
|
5591
|
+
* key. This is what stops a dead runner's teardown from erasing its
|
|
5592
|
+
* successor's live registration ([D188](../../../../docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md)).
|
|
5593
|
+
*/
|
|
5594
|
+
unregisterProvider(capabilityName, addonId, owner) {
|
|
5539
5595
|
const state = this.capabilities.get(capabilityName);
|
|
5540
5596
|
if (!state) return;
|
|
5597
|
+
const registeredOwner = state.providerOwners.get(addonId);
|
|
5598
|
+
if (registeredOwner !== void 0 && registeredOwner !== owner) {
|
|
5599
|
+
this.logger.info("Unregister ignored — registration is owned by another incarnation", {
|
|
5600
|
+
tags: { addonId },
|
|
5601
|
+
meta: {
|
|
5602
|
+
capability: capabilityName,
|
|
5603
|
+
registeredOwner,
|
|
5604
|
+
presentedOwner: owner ?? null
|
|
5605
|
+
}
|
|
5606
|
+
});
|
|
5607
|
+
return;
|
|
5608
|
+
}
|
|
5541
5609
|
state.providers.delete(addonId);
|
|
5610
|
+
state.providerOwners.delete(addonId);
|
|
5542
5611
|
if (state.definition.mode === "singleton" && state.activeAddonId === addonId) {
|
|
5543
5612
|
const userChoice = this.configReader?.(capabilityName);
|
|
5544
5613
|
const preferred = state.definition.preferredProvider;
|
|
@@ -94555,6 +94624,11 @@ var JobJournal = class {
|
|
|
94555
94624
|
function safeSegment(name) {
|
|
94556
94625
|
return name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
94557
94626
|
}
|
|
94627
|
+
/** An exact semver — the only shape the staged package.json can be compared
|
|
94628
|
+
* against literally. Anything else ('latest', 'beta', a range) is a dist-tag
|
|
94629
|
+
* the FETCHER resolves; comparing the resolved version to the literal tag
|
|
94630
|
+
* failed every tag-based update (30/30 on 2026-08-20). */
|
|
94631
|
+
var EXACT_SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
94558
94632
|
var StagingArea = class {
|
|
94559
94633
|
stagingDir;
|
|
94560
94634
|
deps;
|
|
@@ -94572,8 +94646,12 @@ var StagingArea = class {
|
|
|
94572
94646
|
if (input.signal.aborted) throw new Error("staging aborted after fetch");
|
|
94573
94647
|
await this.deps.extract(tgz, destDir);
|
|
94574
94648
|
const raw = JSON.parse(node_fs.readFileSync(node_path.join(destDir, "package.json"), "utf-8"));
|
|
94575
|
-
if (raw.version !==
|
|
94576
|
-
|
|
94649
|
+
if (typeof raw.version !== "string" || raw.version.length === 0) throw new Error(`staging validation failed: ${input.name} staged a package.json with no version`);
|
|
94650
|
+
if (EXACT_SEMVER.test(input.version) && raw.version !== input.version) throw new Error(`staging validation failed: ${input.name} expected version ${input.version}, got ${raw.version}`);
|
|
94651
|
+
return {
|
|
94652
|
+
stagedPath: destDir,
|
|
94653
|
+
resolvedVersion: raw.version
|
|
94654
|
+
};
|
|
94577
94655
|
}
|
|
94578
94656
|
cleanup(jobId) {
|
|
94579
94657
|
node_fs.rmSync(node_path.join(this.stagingDir, jobId), {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-
|
|
2
|
+
import { At as asNumber, B as extractNestedAddonId, Bt as parseJsonUnknown$1, Dt as ReadinessTimeoutError, Et as ReadinessRegistry, Ft as expandCapMethods, Gt as EventCategory$1, H as isArrayOutputSchema, Ht as resolveCapMount, J as lifecycleJobSchema, K as isVoidInput, Mt as createEvent, Nt as emitDownForOwnedCaps, Q as looseSchema, St as DEVICE_STATUS_METHOD, U as isCollectionArrayMethod, Ut as scopeKey, Vt as readinessKey, W as isObjectInput, Z as logLevelAtMost, bt as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, it as procedureAuthKey, jt as asString$1, kt as asJsonObject$1, ot as scopesAllowAddon, q as kebabToCamel, st as scopesAllowDeviceCap, t as ALL_CAPABILITY_DEFINITIONS, tt as objectInputDeclaresAddonId, vt as errMsg$1, xt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, y as addonSettingsCapability, zt as parseJsonObject } from "./dist-CW4Cims4.mjs";
|
|
3
3
|
import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
|
|
4
4
|
import "./builtins/alerts/index.mjs";
|
|
5
5
|
import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
|
|
@@ -24,7 +24,7 @@ import { SystemConfigAddon } from "./builtins/system-config/system-config.addon.
|
|
|
24
24
|
import "./builtins/system-config/index.mjs";
|
|
25
25
|
import { WinstonDestination, WinstonLoggingAddon } from "./builtins/winston-logging/index.mjs";
|
|
26
26
|
import { a as parseTokenizedUrl, c as collectModelFiles, d as downloadModel, f as ensureModel, h as isModelDownloaded, i as parseRangeHeader, l as deleteModelFromDisk, m as getModelFilePath, n as contentTypeFor, o as resolveFilePath, p as fetchJson, r as createAuthenticatedFileServer, s as ModelDownloadService, t as createFileDataPlaneHandler, u as downloadFile } from "./file-data-plane-CuE_hBli.mjs";
|
|
27
|
-
import { $ as buildNativeCapProxy, A as createHubCapForwardService, At as buildHeapSample, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, Dt as HEAP_WATCH_INTERVAL_MS, E as ipcParentLink, Et as HEAP_RECLAIM_TRIGGER_MB, F as createUdsLogger, Ft as strandedMb, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, Mt as shouldReclaim, N as createUdsEventBus, Nt as startHeapWatch, O as HUB_CAP_FWD_ACTION, Ot as HEAP_WATCH_WARN_RATIO, P as udsChildLogToWorkerEntry, Pt as startRunnerHeapWatch, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, Tt as HEAP_RECLAIM_MIN_INTERVAL_MS, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, jt as createV8Reclaimer, k as HUB_CAP_FWD_SERVICE, kt as RUNNER_HEAP_WATCH_INTERVAL_MS, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-
|
|
27
|
+
import { $ as buildNativeCapProxy, A as createHubCapForwardService, At as buildHeapSample, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as runNpm, D as localProviderLink, Dt as HEAP_WATCH_INTERVAL_MS, E as ipcParentLink, Et as HEAP_RECLAIM_TRIGGER_MB, F as createUdsLogger, Ft as strandedMb, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, Mt as shouldReclaim, N as createUdsEventBus, Nt as startHeapWatch, O as HUB_CAP_FWD_ACTION, Ot as HEAP_WATCH_WARN_RATIO, P as udsChildLogToWorkerEntry, Pt as startRunnerHeapWatch, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as resolveNpmInvocation, T as ipcChildLink, Tt as HEAP_RECLAIM_MIN_INTERVAL_MS, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, jt as createV8Reclaimer, k as HUB_CAP_FWD_SERVICE, kt as RUNNER_HEAP_WATCH_INTERVAL_MS, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveAddonClass, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-Cb1ANt3i.mjs";
|
|
28
28
|
import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BWmQ5i-o.mjs";
|
|
29
29
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
30
30
|
import { z } from "zod";
|
|
@@ -5360,6 +5360,7 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5360
5360
|
const state = {
|
|
5361
5361
|
definition,
|
|
5362
5362
|
providers: /* @__PURE__ */ new Map(),
|
|
5363
|
+
providerOwners: /* @__PURE__ */ new Map(),
|
|
5363
5364
|
activeAddonId: null,
|
|
5364
5365
|
router: null,
|
|
5365
5366
|
disabledProviders: /* @__PURE__ */ new Set()
|
|
@@ -5417,8 +5418,15 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5417
5418
|
* Double-register of the same pair is always a programmer error —
|
|
5418
5419
|
* two legitimately different addons implementing the same cap keep
|
|
5419
5420
|
* using different `addonId`s and the user picks one via `configReader`.
|
|
5420
|
-
|
|
5421
|
-
|
|
5421
|
+
*
|
|
5422
|
+
* `owner` (optional) stamps the registration with the incarnation that made
|
|
5423
|
+
* it — see {@link ProviderOwnerToken}. Once stamped, only an unregister
|
|
5424
|
+
* presenting the SAME token can delete it. Registration paths whose key is
|
|
5425
|
+
* reused across process generations (the UDS child manifest, the D3
|
|
5426
|
+
* `registerNode` handshake) MUST pass one; ownerless registrations keep the
|
|
5427
|
+
* historical unconditional behaviour.
|
|
5428
|
+
*/
|
|
5429
|
+
registerProvider(capabilityName, addonId, provider, owner) {
|
|
5422
5430
|
let state = this.capabilities.get(capabilityName);
|
|
5423
5431
|
if (!state) {
|
|
5424
5432
|
const colonIdx = capabilityName.indexOf(":");
|
|
@@ -5450,6 +5458,7 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5450
5458
|
if (missing.length > 0) throw new Error(`CapabilityRegistry: provider "${addonId}" for capability "${capabilityName}" declares exposesDeviceSettings: true but is missing DeviceSettingsContribution method(s): ${missing.join(", ")}. Implement them on the provider (or drop the flag from the cap def).`);
|
|
5451
5459
|
}
|
|
5452
5460
|
state.providers.set(addonId, provider);
|
|
5461
|
+
if (owner !== void 0) state.providerOwners.set(addonId, owner);
|
|
5453
5462
|
if (state.definition.mode === "singleton") {
|
|
5454
5463
|
const userChoice = this.configReader?.(capabilityName);
|
|
5455
5464
|
const preferred = state.definition.preferredProvider;
|
|
@@ -5480,7 +5489,8 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5480
5489
|
tags: { addonId },
|
|
5481
5490
|
meta: {
|
|
5482
5491
|
capability: capabilityName,
|
|
5483
|
-
mode: state.definition.mode
|
|
5492
|
+
mode: state.definition.mode,
|
|
5493
|
+
...owner === void 0 ? {} : { owner }
|
|
5484
5494
|
}
|
|
5485
5495
|
});
|
|
5486
5496
|
this.emitEvent("capability:provider-registered", {
|
|
@@ -5527,11 +5537,70 @@ var CapabilityRegistry = class CapabilityRegistry {
|
|
|
5527
5537
|
const declarers = this.manifestDeclarers.get(capabilityName);
|
|
5528
5538
|
return declarers ? [...declarers] : [];
|
|
5529
5539
|
}
|
|
5530
|
-
/**
|
|
5531
|
-
|
|
5540
|
+
/**
|
|
5541
|
+
* The owner token a registration declared, or `null` when the pair is not
|
|
5542
|
+
* registered or was registered without one.
|
|
5543
|
+
*/
|
|
5544
|
+
getProviderOwner(capabilityName, addonId) {
|
|
5545
|
+
return this.capabilities.get(capabilityName)?.providerOwners.get(addonId) ?? null;
|
|
5546
|
+
}
|
|
5547
|
+
/**
|
|
5548
|
+
* Hand an EXISTING registration to a new owner, without touching the provider
|
|
5549
|
+
* instance, the active-singleton selection or any event.
|
|
5550
|
+
*
|
|
5551
|
+
* The takeover case: a replacement runner handshakes with an UNCHANGED cap
|
|
5552
|
+
* set, so the manifest diff correctly leaves the registration alone — but the
|
|
5553
|
+
* registration is still stamped with the dead generation's token, and nothing
|
|
5554
|
+
* the LIVE generation can present would ever match it. Re-stamping keeps the
|
|
5555
|
+
* capability cleanable when the successor eventually dies.
|
|
5556
|
+
*
|
|
5557
|
+
* Returns `false` when the pair is not registered (nothing to hand over) —
|
|
5558
|
+
* the caller decides whether that is a register-instead or a diagnosis.
|
|
5559
|
+
*/
|
|
5560
|
+
reassignProviderOwner(capabilityName, addonId, owner) {
|
|
5561
|
+
const state = this.capabilities.get(capabilityName);
|
|
5562
|
+
if (!state || !state.providers.has(addonId)) return false;
|
|
5563
|
+
const previous = state.providerOwners.get(addonId);
|
|
5564
|
+
if (previous === owner) return true;
|
|
5565
|
+
state.providerOwners.set(addonId, owner);
|
|
5566
|
+
this.logger.info("Capability registration ownership reassigned", {
|
|
5567
|
+
tags: { addonId },
|
|
5568
|
+
meta: {
|
|
5569
|
+
capability: capabilityName,
|
|
5570
|
+
owner,
|
|
5571
|
+
previousOwner: previous ?? null
|
|
5572
|
+
}
|
|
5573
|
+
});
|
|
5574
|
+
return true;
|
|
5575
|
+
}
|
|
5576
|
+
/**
|
|
5577
|
+
* Unregister a provider. For singleton: clears active. For collection:
|
|
5578
|
+
* removes from list.
|
|
5579
|
+
*
|
|
5580
|
+
* `owner` is the caller's PROOF that it owns the registration it is deleting.
|
|
5581
|
+
* When the registration declared an owner (see {@link ProviderOwnerToken})
|
|
5582
|
+
* and the caller presents a different one — or none at all — this is a
|
|
5583
|
+
* logged no-op: the caller belongs to a generation that no longer holds the
|
|
5584
|
+
* key. This is what stops a dead runner's teardown from erasing its
|
|
5585
|
+
* successor's live registration ([D188](../../../../docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md)).
|
|
5586
|
+
*/
|
|
5587
|
+
unregisterProvider(capabilityName, addonId, owner) {
|
|
5532
5588
|
const state = this.capabilities.get(capabilityName);
|
|
5533
5589
|
if (!state) return;
|
|
5590
|
+
const registeredOwner = state.providerOwners.get(addonId);
|
|
5591
|
+
if (registeredOwner !== void 0 && registeredOwner !== owner) {
|
|
5592
|
+
this.logger.info("Unregister ignored — registration is owned by another incarnation", {
|
|
5593
|
+
tags: { addonId },
|
|
5594
|
+
meta: {
|
|
5595
|
+
capability: capabilityName,
|
|
5596
|
+
registeredOwner,
|
|
5597
|
+
presentedOwner: owner ?? null
|
|
5598
|
+
}
|
|
5599
|
+
});
|
|
5600
|
+
return;
|
|
5601
|
+
}
|
|
5534
5602
|
state.providers.delete(addonId);
|
|
5603
|
+
state.providerOwners.delete(addonId);
|
|
5535
5604
|
if (state.definition.mode === "singleton" && state.activeAddonId === addonId) {
|
|
5536
5605
|
const userChoice = this.configReader?.(capabilityName);
|
|
5537
5606
|
const preferred = state.definition.preferredProvider;
|
|
@@ -94548,6 +94617,11 @@ var JobJournal = class {
|
|
|
94548
94617
|
function safeSegment(name) {
|
|
94549
94618
|
return name.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
94550
94619
|
}
|
|
94620
|
+
/** An exact semver — the only shape the staged package.json can be compared
|
|
94621
|
+
* against literally. Anything else ('latest', 'beta', a range) is a dist-tag
|
|
94622
|
+
* the FETCHER resolves; comparing the resolved version to the literal tag
|
|
94623
|
+
* failed every tag-based update (30/30 on 2026-08-20). */
|
|
94624
|
+
var EXACT_SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
94551
94625
|
var StagingArea = class {
|
|
94552
94626
|
stagingDir;
|
|
94553
94627
|
deps;
|
|
@@ -94565,8 +94639,12 @@ var StagingArea = class {
|
|
|
94565
94639
|
if (input.signal.aborted) throw new Error("staging aborted after fetch");
|
|
94566
94640
|
await this.deps.extract(tgz, destDir);
|
|
94567
94641
|
const raw = JSON.parse(fs$17.readFileSync(path$39.join(destDir, "package.json"), "utf-8"));
|
|
94568
|
-
if (raw.version !==
|
|
94569
|
-
|
|
94642
|
+
if (typeof raw.version !== "string" || raw.version.length === 0) throw new Error(`staging validation failed: ${input.name} staged a package.json with no version`);
|
|
94643
|
+
if (EXACT_SEMVER.test(input.version) && raw.version !== input.version) throw new Error(`staging validation failed: ${input.name} expected version ${input.version}, got ${raw.version}`);
|
|
94644
|
+
return {
|
|
94645
|
+
stagedPath: destDir,
|
|
94646
|
+
resolvedVersion: raw.version
|
|
94647
|
+
};
|
|
94570
94648
|
}
|
|
94571
94649
|
cleanup(jobId) {
|
|
94572
94650
|
fs$17.rmSync(path$39.join(this.stagingDir, jobId), {
|
|
@@ -19,6 +19,18 @@ export type ConfigReader = (capability: string) => string | undefined;
|
|
|
19
19
|
* {@link ConfigReader} does for singletons.
|
|
20
20
|
*/
|
|
21
21
|
export type CollectionConfigReader = (capability: string) => readonly string[] | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Proof that an unregister owns the registration it is about to delete.
|
|
24
|
+
*
|
|
25
|
+
* A `(capability, addonId)` key is NOT unique over time: a runner replaced by
|
|
26
|
+
* an update re-registers under the exact same key (`resolveRunnerId` is
|
|
27
|
+
* deterministic), so the dead generation's teardown and the live generation's
|
|
28
|
+
* registration are indistinguishable by key alone. The owner token names the
|
|
29
|
+
* INCARNATION that made a registration — e.g. `hub/recorder#7` — and
|
|
30
|
+
* {@link CapabilityRegistry.unregisterProvider} refuses any unregister that
|
|
31
|
+
* cannot present it. See docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md.
|
|
32
|
+
*/
|
|
33
|
+
export type ProviderOwnerToken = string;
|
|
22
34
|
export declare class CapabilityRegistry {
|
|
23
35
|
private readonly capabilities;
|
|
24
36
|
private readonly logger;
|
|
@@ -148,8 +160,15 @@ export declare class CapabilityRegistry {
|
|
|
148
160
|
* Double-register of the same pair is always a programmer error —
|
|
149
161
|
* two legitimately different addons implementing the same cap keep
|
|
150
162
|
* using different `addonId`s and the user picks one via `configReader`.
|
|
163
|
+
*
|
|
164
|
+
* `owner` (optional) stamps the registration with the incarnation that made
|
|
165
|
+
* it — see {@link ProviderOwnerToken}. Once stamped, only an unregister
|
|
166
|
+
* presenting the SAME token can delete it. Registration paths whose key is
|
|
167
|
+
* reused across process generations (the UDS child manifest, the D3
|
|
168
|
+
* `registerNode` handshake) MUST pass one; ownerless registrations keep the
|
|
169
|
+
* historical unconditional behaviour.
|
|
151
170
|
*/
|
|
152
|
-
registerProvider(capabilityName: string, addonId: string, provider: unknown): void;
|
|
171
|
+
registerProvider(capabilityName: string, addonId: string, provider: unknown, owner?: ProviderOwnerToken): void;
|
|
153
172
|
/**
|
|
154
173
|
* Whether a provider for the exact `(capabilityName, addonId)` pair is
|
|
155
174
|
* currently registered. Lets a re-registration path (e.g. the agent's
|
|
@@ -173,8 +192,37 @@ export declare class CapabilityRegistry {
|
|
|
173
192
|
* it is the diagnosis).
|
|
174
193
|
*/
|
|
175
194
|
getManifestDeclarers(capabilityName: string): readonly string[];
|
|
176
|
-
/**
|
|
177
|
-
|
|
195
|
+
/**
|
|
196
|
+
* The owner token a registration declared, or `null` when the pair is not
|
|
197
|
+
* registered or was registered without one.
|
|
198
|
+
*/
|
|
199
|
+
getProviderOwner(capabilityName: string, addonId: string): ProviderOwnerToken | null;
|
|
200
|
+
/**
|
|
201
|
+
* Hand an EXISTING registration to a new owner, without touching the provider
|
|
202
|
+
* instance, the active-singleton selection or any event.
|
|
203
|
+
*
|
|
204
|
+
* The takeover case: a replacement runner handshakes with an UNCHANGED cap
|
|
205
|
+
* set, so the manifest diff correctly leaves the registration alone — but the
|
|
206
|
+
* registration is still stamped with the dead generation's token, and nothing
|
|
207
|
+
* the LIVE generation can present would ever match it. Re-stamping keeps the
|
|
208
|
+
* capability cleanable when the successor eventually dies.
|
|
209
|
+
*
|
|
210
|
+
* Returns `false` when the pair is not registered (nothing to hand over) —
|
|
211
|
+
* the caller decides whether that is a register-instead or a diagnosis.
|
|
212
|
+
*/
|
|
213
|
+
reassignProviderOwner(capabilityName: string, addonId: string, owner: ProviderOwnerToken): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Unregister a provider. For singleton: clears active. For collection:
|
|
216
|
+
* removes from list.
|
|
217
|
+
*
|
|
218
|
+
* `owner` is the caller's PROOF that it owns the registration it is deleting.
|
|
219
|
+
* When the registration declared an owner (see {@link ProviderOwnerToken})
|
|
220
|
+
* and the caller presents a different one — or none at all — this is a
|
|
221
|
+
* logged no-op: the caller belongs to a generation that no longer holds the
|
|
222
|
+
* key. This is what stops a dead runner's teardown from erasing its
|
|
223
|
+
* successor's live registration ([D188](../../../../docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md)).
|
|
224
|
+
*/
|
|
225
|
+
unregisterProvider(capabilityName: string, addonId: string, owner?: ProviderOwnerToken): void;
|
|
178
226
|
/** Enable a previously disabled collection provider. */
|
|
179
227
|
enableCollectionProvider(capability: string, addonId: string): void;
|
|
180
228
|
/** Disable a collection provider (keeps it registered but excluded from active list). */
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The bare specifiers an ESM addon may leave unbundled and expect the HOST
|
|
3
3
|
* framework to provide. Self-contained addons (the standard) inline
|
|
4
4
|
* @camstack/types, @camstack/sdk, zod, @trpc/* — so for them only
|
|
5
|
-
* @camstack/system
|
|
5
|
+
* @camstack/system survives as genuinely host-provided. Framework-mode (legacy)
|
|
6
6
|
* addons additionally leave the types/sdk/zod/trpc set external. Listing the
|
|
7
7
|
* full union here lets one resolver hook serve both modes: for a self-contained
|
|
8
8
|
* addon the extra entries simply never appear as live imports.
|
package/dist/kernel/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export { buildCapRouters, builderMountedCapNames } from './cap-router-builder.js
|
|
|
17
17
|
export type { CapRouterPrimitives, CapRouterServices, CapProviderGetter, RemoteProxyFactory, ProcedureBuilder, ProcedureResolverArgs, } from './cap-router-builder.js';
|
|
18
18
|
export { describeProviderKindDrift } from './provider-kind-drift.js';
|
|
19
19
|
export type { ProviderKindHint } from './provider-kind-drift.js';
|
|
20
|
-
export type { CapabilityRouter, CapabilityRouterFactory, ConfigReader, } from './capability-registry.js';
|
|
20
|
+
export type { CapabilityRouter, CapabilityRouterFactory, ConfigReader, ProviderOwnerToken, } from './capability-registry.js';
|
|
21
21
|
export { CustomActionRegistry, type CustomActionEntry } from './custom-action-registry.js';
|
|
22
22
|
export { INFRA_CAPABILITIES, isInfraCapability } from './infra-capabilities.js';
|
|
23
23
|
export type { InfraCapability } from './infra-capabilities.js';
|
|
@@ -222,6 +222,18 @@ export type ParentToChildRequest = CapCallMessage | ParentEventMessage | Readine
|
|
|
222
222
|
export interface RegisteredChild {
|
|
223
223
|
readonly childId: string;
|
|
224
224
|
readonly caps: readonly ChildCapDescriptor[];
|
|
225
|
+
/**
|
|
226
|
+
* Monotonic id of the CONNECTION this registration arrived on, unique within
|
|
227
|
+
* the parent process.
|
|
228
|
+
*
|
|
229
|
+
* `childId` is deterministic (`resolveRunnerId`), so a runner replaced by an
|
|
230
|
+
* update reconnects under the exact same id — the two generations are
|
|
231
|
+
* indistinguishable without this. Consumers stamp it onto whatever they
|
|
232
|
+
* derive from the child (capability registrations, subtree manifests) so a
|
|
233
|
+
* teardown arriving from the DEAD generation can be told apart from the live
|
|
234
|
+
* one. See docs/decisions/adr-0188-an-unregister-carries-proof-of-ownership.md.
|
|
235
|
+
*/
|
|
236
|
+
readonly incarnation: number;
|
|
225
237
|
}
|
|
226
238
|
/** Arguments to route a cap method call (the `cap-call` message minus its discriminant). */
|
|
227
239
|
export type CapCallInput = Omit<CapCallMessage, 'kind'>;
|
|
@@ -139,6 +139,8 @@ export declare class LocalChildRegistry {
|
|
|
139
139
|
private readonly children;
|
|
140
140
|
private registeredHandler;
|
|
141
141
|
private goneHandler;
|
|
142
|
+
/** Source of {@link RegisteredChild.incarnation}; one bump per accepted connection. */
|
|
143
|
+
private nextIncarnation;
|
|
142
144
|
private eventHandler;
|
|
143
145
|
private logHandler;
|
|
144
146
|
private readinessHandler;
|
|
@@ -291,8 +293,13 @@ export declare class LocalChildRegistry {
|
|
|
291
293
|
listChildren(): readonly RegisteredChild[];
|
|
292
294
|
/** Register the (single) child-registered handler. Only one handler is active at a time. */
|
|
293
295
|
onChildRegistered(handler: (child: RegisteredChild) => void): void;
|
|
294
|
-
/**
|
|
295
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Register the (single) child-gone handler. Only one handler is active at a
|
|
298
|
+
* time. The handler receives the {@link RegisteredChild.incarnation} of the
|
|
299
|
+
* connection that closed — carry it into whatever teardown it triggers, so a
|
|
300
|
+
* dead generation cannot tear down its successor's work.
|
|
301
|
+
*/
|
|
302
|
+
onChildGone(handler: (childId: string, incarnation: number) => void): void;
|
|
296
303
|
/**
|
|
297
304
|
* Register the (single) child-event handler. Invoked when a child sends an
|
|
298
305
|
* event via `LocalChildClient.emitEvent`. Only one handler is active at a
|