@camstack/addon-model-studio 1.1.328 → 1.1.329
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/CHANGELOG.md +6 -0
- package/dist/model-studio.addon.js +69 -15
- package/dist/model-studio.addon.mjs +69 -15
- package/package.json +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.329] - 2026-10-31
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Forgetting a node now removes its entries from the model Library 'On nodes' list
|
|
15
|
+
|
|
10
16
|
## [1.1.328] - 2026-10-30
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -44698,14 +44698,24 @@ method(object({
|
|
|
44698
44698
|
kind: "mutation",
|
|
44699
44699
|
auth: "admin"
|
|
44700
44700
|
});
|
|
44701
|
-
|
|
44702
|
-
|
|
44703
|
-
|
|
44704
|
-
|
|
44705
|
-
|
|
44706
|
-
|
|
44707
|
-
|
|
44708
|
-
|
|
44701
|
+
var nodeRemovalHookCapability = {
|
|
44702
|
+
name: "node-removal-hook",
|
|
44703
|
+
scope: "system",
|
|
44704
|
+
mode: "collection",
|
|
44705
|
+
internal: true,
|
|
44706
|
+
methods: {
|
|
44707
|
+
/** Remove or re-point everything this addon keeps for the forgotten node. Idempotent. */
|
|
44708
|
+
onNodeRemoved: method(object({
|
|
44709
|
+
nodeId: string().min(1),
|
|
44710
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
44711
|
+
removedAt: number()
|
|
44712
|
+
}), object({ counts: record(string(), number().int().nonnegative()) }), {
|
|
44713
|
+
kind: "mutation",
|
|
44714
|
+
auth: "admin"
|
|
44715
|
+
}) },
|
|
44716
|
+
/** In-process only — enumerated through `addons.listCapabilityProviders`. */
|
|
44717
|
+
mount: { kind: "skip" }
|
|
44718
|
+
};
|
|
44709
44719
|
/**
|
|
44710
44720
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
44711
44721
|
* so it can delete what it keeps for that device (D865).
|
|
@@ -87880,6 +87890,41 @@ function stripModelIdFromInferenceDevices(devices, modelId) {
|
|
|
87880
87890
|
};
|
|
87881
87891
|
}
|
|
87882
87892
|
//#endregion
|
|
87893
|
+
//#region src/node-removal.ts
|
|
87894
|
+
/** `map` without `nodeId`'s entries, and how many (model, node) entries went. */
|
|
87895
|
+
function clearNodeAvailability(map, nodeId) {
|
|
87896
|
+
const next = {};
|
|
87897
|
+
let cleared = 0;
|
|
87898
|
+
for (const [modelId, perNode] of Object.entries(map)) {
|
|
87899
|
+
if (!(nodeId in perNode)) {
|
|
87900
|
+
next[modelId] = perNode;
|
|
87901
|
+
continue;
|
|
87902
|
+
}
|
|
87903
|
+
cleared += 1;
|
|
87904
|
+
const { [nodeId]: _gone, ...rest } = perNode;
|
|
87905
|
+
if (Object.keys(rest).length > 0) next[modelId] = rest;
|
|
87906
|
+
}
|
|
87907
|
+
return {
|
|
87908
|
+
next,
|
|
87909
|
+
cleared
|
|
87910
|
+
};
|
|
87911
|
+
}
|
|
87912
|
+
function createNodeRemovalHook(deps) {
|
|
87913
|
+
return { onNodeRemoved: async ({ nodeId }) => {
|
|
87914
|
+
let cleared = 0;
|
|
87915
|
+
await deps.availability().update((prev) => {
|
|
87916
|
+
const result = clearNodeAvailability(prev, nodeId);
|
|
87917
|
+
cleared = result.cleared;
|
|
87918
|
+
return cleared === 0 ? prev : result.next;
|
|
87919
|
+
});
|
|
87920
|
+
deps.logger.info("cleared model availability of a forgotten node", {
|
|
87921
|
+
tags: { nodeId },
|
|
87922
|
+
meta: { cleared }
|
|
87923
|
+
});
|
|
87924
|
+
return { counts: { "model-availability": cleared } };
|
|
87925
|
+
} };
|
|
87926
|
+
}
|
|
87927
|
+
//#endregion
|
|
87883
87928
|
//#region src/plus-catalog/plus-catalog-import.ts
|
|
87884
87929
|
/**
|
|
87885
87930
|
* Variant-selector axes for an imported plus catalog / plus catalog detector. Family
|
|
@@ -89321,13 +89366,22 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
89321
89366
|
capability: addonPagesSourceCapability,
|
|
89322
89367
|
provider: pagesProvider
|
|
89323
89368
|
}];
|
|
89324
|
-
if (isHub)
|
|
89325
|
-
|
|
89326
|
-
|
|
89327
|
-
|
|
89328
|
-
|
|
89329
|
-
|
|
89330
|
-
|
|
89369
|
+
if (isHub) {
|
|
89370
|
+
providers.push({
|
|
89371
|
+
capability: customModelRegistryCapability,
|
|
89372
|
+
provider: {
|
|
89373
|
+
listModels: async () => state.get(),
|
|
89374
|
+
importModelBundle: async (input) => this.importModelBundle_(input)
|
|
89375
|
+
}
|
|
89376
|
+
});
|
|
89377
|
+
providers.push({
|
|
89378
|
+
capability: nodeRemovalHookCapability,
|
|
89379
|
+
provider: createNodeRemovalHook({
|
|
89380
|
+
availability: () => this.availability_,
|
|
89381
|
+
logger: this.ctx.logger.child("node-removal")
|
|
89382
|
+
})
|
|
89383
|
+
});
|
|
89384
|
+
}
|
|
89331
89385
|
return {
|
|
89332
89386
|
providers,
|
|
89333
89387
|
customActions: isHub ? modelStudioActions : void 0,
|
|
@@ -44672,14 +44672,24 @@ method(object({
|
|
|
44672
44672
|
kind: "mutation",
|
|
44673
44673
|
auth: "admin"
|
|
44674
44674
|
});
|
|
44675
|
-
|
|
44676
|
-
|
|
44677
|
-
|
|
44678
|
-
|
|
44679
|
-
|
|
44680
|
-
|
|
44681
|
-
|
|
44682
|
-
|
|
44675
|
+
var nodeRemovalHookCapability = {
|
|
44676
|
+
name: "node-removal-hook",
|
|
44677
|
+
scope: "system",
|
|
44678
|
+
mode: "collection",
|
|
44679
|
+
internal: true,
|
|
44680
|
+
methods: {
|
|
44681
|
+
/** Remove or re-point everything this addon keeps for the forgotten node. Idempotent. */
|
|
44682
|
+
onNodeRemoved: method(object({
|
|
44683
|
+
nodeId: string().min(1),
|
|
44684
|
+
/** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
|
|
44685
|
+
removedAt: number()
|
|
44686
|
+
}), object({ counts: record(string(), number().int().nonnegative()) }), {
|
|
44687
|
+
kind: "mutation",
|
|
44688
|
+
auth: "admin"
|
|
44689
|
+
}) },
|
|
44690
|
+
/** In-process only — enumerated through `addons.listCapabilityProviders`. */
|
|
44691
|
+
mount: { kind: "skip" }
|
|
44692
|
+
};
|
|
44683
44693
|
/**
|
|
44684
44694
|
* `device-removal-hook` — the reliable way an addon learns a device was DELETED,
|
|
44685
44695
|
* so it can delete what it keeps for that device (D865).
|
|
@@ -87854,6 +87864,41 @@ function stripModelIdFromInferenceDevices(devices, modelId) {
|
|
|
87854
87864
|
};
|
|
87855
87865
|
}
|
|
87856
87866
|
//#endregion
|
|
87867
|
+
//#region src/node-removal.ts
|
|
87868
|
+
/** `map` without `nodeId`'s entries, and how many (model, node) entries went. */
|
|
87869
|
+
function clearNodeAvailability(map, nodeId) {
|
|
87870
|
+
const next = {};
|
|
87871
|
+
let cleared = 0;
|
|
87872
|
+
for (const [modelId, perNode] of Object.entries(map)) {
|
|
87873
|
+
if (!(nodeId in perNode)) {
|
|
87874
|
+
next[modelId] = perNode;
|
|
87875
|
+
continue;
|
|
87876
|
+
}
|
|
87877
|
+
cleared += 1;
|
|
87878
|
+
const { [nodeId]: _gone, ...rest } = perNode;
|
|
87879
|
+
if (Object.keys(rest).length > 0) next[modelId] = rest;
|
|
87880
|
+
}
|
|
87881
|
+
return {
|
|
87882
|
+
next,
|
|
87883
|
+
cleared
|
|
87884
|
+
};
|
|
87885
|
+
}
|
|
87886
|
+
function createNodeRemovalHook(deps) {
|
|
87887
|
+
return { onNodeRemoved: async ({ nodeId }) => {
|
|
87888
|
+
let cleared = 0;
|
|
87889
|
+
await deps.availability().update((prev) => {
|
|
87890
|
+
const result = clearNodeAvailability(prev, nodeId);
|
|
87891
|
+
cleared = result.cleared;
|
|
87892
|
+
return cleared === 0 ? prev : result.next;
|
|
87893
|
+
});
|
|
87894
|
+
deps.logger.info("cleared model availability of a forgotten node", {
|
|
87895
|
+
tags: { nodeId },
|
|
87896
|
+
meta: { cleared }
|
|
87897
|
+
});
|
|
87898
|
+
return { counts: { "model-availability": cleared } };
|
|
87899
|
+
} };
|
|
87900
|
+
}
|
|
87901
|
+
//#endregion
|
|
87857
87902
|
//#region src/plus-catalog/plus-catalog-import.ts
|
|
87858
87903
|
/**
|
|
87859
87904
|
* Variant-selector axes for an imported plus catalog / plus catalog detector. Family
|
|
@@ -89295,13 +89340,22 @@ var ModelStudioAddon = class ModelStudioAddon extends BaseAddon {
|
|
|
89295
89340
|
capability: addonPagesSourceCapability,
|
|
89296
89341
|
provider: pagesProvider
|
|
89297
89342
|
}];
|
|
89298
|
-
if (isHub)
|
|
89299
|
-
|
|
89300
|
-
|
|
89301
|
-
|
|
89302
|
-
|
|
89303
|
-
|
|
89304
|
-
|
|
89343
|
+
if (isHub) {
|
|
89344
|
+
providers.push({
|
|
89345
|
+
capability: customModelRegistryCapability,
|
|
89346
|
+
provider: {
|
|
89347
|
+
listModels: async () => state.get(),
|
|
89348
|
+
importModelBundle: async (input) => this.importModelBundle_(input)
|
|
89349
|
+
}
|
|
89350
|
+
});
|
|
89351
|
+
providers.push({
|
|
89352
|
+
capability: nodeRemovalHookCapability,
|
|
89353
|
+
provider: createNodeRemovalHook({
|
|
89354
|
+
availability: () => this.availability_,
|
|
89355
|
+
logger: this.ctx.logger.child("node-removal")
|
|
89356
|
+
})
|
|
89357
|
+
});
|
|
89358
|
+
}
|
|
89305
89359
|
return {
|
|
89306
89360
|
providers,
|
|
89307
89361
|
customActions: isHub ? modelStudioActions : void 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-model-studio",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.329",
|
|
4
4
|
"description": "Custom detection model registry, conversion & distribution for CamStack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -53,6 +53,9 @@
|
|
|
53
53
|
{
|
|
54
54
|
"name": "model-convert"
|
|
55
55
|
},
|
|
56
|
+
{
|
|
57
|
+
"name": "node-removal-hook"
|
|
58
|
+
},
|
|
56
59
|
{
|
|
57
60
|
"name": "addon-pages-source"
|
|
58
61
|
}
|