@camstack/system 1.2.68 → 1.2.70

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.
Files changed (70) hide show
  1. package/dist/addon-runner.js +6 -6
  2. package/dist/addon-runner.mjs +3 -3
  3. package/dist/addon-utils.js +11 -11
  4. package/dist/addon-utils.mjs +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +3 -3
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +2 -2
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +3 -3
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +2 -2
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +8 -8
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +6 -6
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/core-blocks/core-blocks.addon.js +3 -3
  16. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  17. package/dist/builtins/device-manager/adoption-job-engine.d.ts +89 -0
  18. package/dist/builtins/device-manager/device-manager.addon.d.ts +8 -0
  19. package/dist/builtins/device-manager/device-manager.addon.js +330 -3
  20. package/dist/builtins/device-manager/device-manager.addon.mjs +330 -3
  21. package/dist/builtins/device-manager/device-provider-context.d.ts +3 -0
  22. package/dist/builtins/device-manager/device-queries.d.ts +3 -0
  23. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  24. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  25. package/dist/builtins/hub-forwarder/index.js +1 -1
  26. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  27. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  28. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  29. package/dist/builtins/local-auth/index.d.ts +0 -1
  30. package/dist/builtins/local-auth/index.js +0 -1
  31. package/dist/builtins/local-auth/index.mjs +2 -2
  32. package/dist/builtins/local-auth/local-auth.addon.js +129 -173
  33. package/dist/builtins/local-auth/local-auth.addon.mjs +130 -173
  34. package/dist/builtins/local-network/local-network.addon.js +1 -1
  35. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  36. package/dist/builtins/loki-logging/index.js +1 -1
  37. package/dist/builtins/loki-logging/index.mjs +1 -1
  38. package/dist/builtins/native-metrics/native-metrics.addon.js +5 -5
  39. package/dist/builtins/native-metrics/native-metrics.addon.mjs +4 -4
  40. package/dist/builtins/platform-probe/index.js +4 -4
  41. package/dist/builtins/platform-probe/index.mjs +3 -3
  42. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  43. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/snapshot/index.js +2 -2
  45. package/dist/builtins/snapshot/index.mjs +2 -2
  46. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -4
  47. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +3 -3
  48. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  49. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  50. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +3 -3
  51. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
  52. package/dist/builtins/system-config/system-config.addon.js +1 -1
  53. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  54. package/dist/builtins/winston-logging/index.js +1 -1
  55. package/dist/builtins/winston-logging/index.mjs +1 -1
  56. package/dist/{dist-D2J8RJ7m.mjs → dist-CnQXXnK1.mjs} +296 -2
  57. package/dist/{dist-Dhpte164.js → dist-DCLoJf2T.js} +295 -7
  58. package/dist/{model-download-service-CTBHzORJ.mjs → file-data-plane-CuE_hBli.mjs} +848 -848
  59. package/dist/index.d.ts +73 -81
  60. package/dist/index.js +1379 -1346
  61. package/dist/index.mjs +1362 -1328
  62. package/dist/kernel/capability-registry.d.ts +26 -0
  63. package/dist/kernel/config-schema.d.ts +1 -1
  64. package/dist/{manifest-python-deps-Dz1ryHIN.mjs → manifest-python-deps-DKrHcUZj.mjs} +47 -47
  65. package/package.json +1 -4
  66. package/dist/builtins/local-auth/homeassistant-integration.d.ts +0 -7
  67. package/dist/{model-download-service-Caj1kaSi.js → file-data-plane-DUHPHa-Y.js} +847 -847
  68. package/dist/{manifest-python-deps-BE6l8Y4W.js → manifest-python-deps-DafB-1hp.js} +47 -47
  69. package/dist/{resource-monitor-BkP504Vq.mjs → resource-monitor-BWmQ5i-o.mjs} +1 -1
  70. package/dist/{resource-monitor-DNNomR-i.js → resource-monitor-CdnzxBLP.js} +1 -1
@@ -3,9 +3,297 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dhpte164.js");
7
- let _camstack_types_node = require("@camstack/types/node");
6
+ const require_dist = require("../../dist-DCLoJf2T.js");
8
7
  let node_crypto = require("node:crypto");
8
+ let _camstack_types_node = require("@camstack/types/node");
9
+ //#region src/builtins/device-manager/adoption-job-engine.ts
10
+ /** How many finished jobs are kept per (addonId, integrationId). */
11
+ var JOB_HISTORY = 20;
12
+ function snapshot(j) {
13
+ let adopted = 0;
14
+ let alreadyAdopted = 0;
15
+ let failed = 0;
16
+ let processed = 0;
17
+ let accessoriesCreated = 0;
18
+ for (const r of j.results) {
19
+ if (r.outcome === "cancelled") continue;
20
+ processed += 1;
21
+ accessoriesCreated += r.accessoryCount;
22
+ if (r.outcome === "adopted") adopted += 1;
23
+ else if (r.outcome === "already-adopted") alreadyAdopted += 1;
24
+ else if (r.outcome === "failed") failed += 1;
25
+ }
26
+ return {
27
+ jobId: j.jobId,
28
+ addonId: j.addonId,
29
+ integrationId: j.integrationId,
30
+ state: j.state,
31
+ total: j.total,
32
+ processed,
33
+ adopted,
34
+ alreadyAdopted,
35
+ failed,
36
+ accessoriesCreated,
37
+ currentChildNativeId: j.currentChildNativeId,
38
+ results: j.results.map((r) => ({
39
+ childNativeId: r.childNativeId,
40
+ outcome: r.outcome,
41
+ parentDeviceId: r.parentDeviceId,
42
+ accessoryCount: r.accessoryCount,
43
+ error: r.error
44
+ })),
45
+ startedAt: j.startedAt,
46
+ finishedAt: j.finishedAt,
47
+ error: j.error
48
+ };
49
+ }
50
+ var AdoptionJobEngine = class {
51
+ deps;
52
+ jobs = /* @__PURE__ */ new Map();
53
+ seq = 0;
54
+ constructor(deps) {
55
+ this.deps = deps;
56
+ }
57
+ now() {
58
+ return this.deps.now?.() ?? Date.now();
59
+ }
60
+ newId() {
61
+ if (this.deps.newId) return this.deps.newId();
62
+ this.seq += 1;
63
+ return `adopt-${Date.now().toString(36)}-${this.seq}`;
64
+ }
65
+ /**
66
+ * Accept the batch and return immediately. The provider is resolved BEFORE
67
+ * returning so an unroutable `addonId` is refused at the call the operator
68
+ * made, not buried in a job they have to go looking for.
69
+ */
70
+ async start(input) {
71
+ const provider = await this.deps.resolveProvider(input.addonId);
72
+ const job = {
73
+ jobId: this.newId(),
74
+ addonId: input.addonId,
75
+ integrationId: input.integrationId,
76
+ state: "running",
77
+ total: input.childNativeIds.length,
78
+ currentChildNativeId: null,
79
+ results: [],
80
+ startedAt: this.now(),
81
+ finishedAt: null,
82
+ error: null,
83
+ cancelRequested: false,
84
+ done: Promise.resolve()
85
+ };
86
+ this.jobs.set(job.jobId, job);
87
+ this.prune(input.addonId, input.integrationId);
88
+ this.deps.logger.info("adoption job started", {
89
+ tags: { addonId: input.addonId },
90
+ meta: {
91
+ jobId: job.jobId,
92
+ integrationId: input.integrationId,
93
+ total: job.total
94
+ }
95
+ });
96
+ job.done = this.run(job, provider, input);
97
+ return { jobId: job.jobId };
98
+ }
99
+ get(jobId) {
100
+ const j = this.jobs.get(jobId);
101
+ return j ? snapshot(j) : null;
102
+ }
103
+ list(filter) {
104
+ return [...this.jobs.values()].filter((j) => (filter.addonId === void 0 || j.addonId === filter.addonId) && (filter.integrationId === void 0 || j.integrationId === filter.integrationId)).sort((a, b) => b.startedAt - a.startedAt || b.jobId.localeCompare(a.jobId)).map(snapshot);
105
+ }
106
+ /** Cooperative cancel — the in-flight candidate finishes, the rest do not start. */
107
+ cancel(jobId) {
108
+ const job = this.jobs.get(jobId);
109
+ if (!job || job.state !== "running") return false;
110
+ job.cancelRequested = true;
111
+ this.deps.logger.info("adoption job cancel requested", {
112
+ tags: { addonId: job.addonId },
113
+ meta: {
114
+ jobId,
115
+ integrationId: job.integrationId
116
+ }
117
+ });
118
+ return true;
119
+ }
120
+ /** Test-only: await the detached loop. Never called by production code. */
121
+ async waitForTest(jobId) {
122
+ await this.jobs.get(jobId)?.done;
123
+ }
124
+ prune(addonId, integrationId) {
125
+ const finished = [...this.jobs.values()].filter((j) => j.addonId === addonId && j.integrationId === integrationId && j.state !== "running").sort((a, b) => b.startedAt - a.startedAt);
126
+ for (const j of finished.slice(JOB_HISTORY)) this.jobs.delete(j.jobId);
127
+ }
128
+ async run(job, provider, input) {
129
+ try {
130
+ const already = await this.alreadyAdopted(provider, input, job);
131
+ for (const childNativeId of input.childNativeIds) {
132
+ if (job.cancelRequested) {
133
+ job.results.push({
134
+ childNativeId,
135
+ outcome: "cancelled",
136
+ parentDeviceId: null,
137
+ accessoryCount: 0,
138
+ error: null
139
+ });
140
+ continue;
141
+ }
142
+ if (already.has(childNativeId)) {
143
+ job.results.push({
144
+ childNativeId,
145
+ outcome: "already-adopted",
146
+ parentDeviceId: null,
147
+ accessoryCount: 0,
148
+ error: null
149
+ });
150
+ this.deps.logger.info("adoption job: candidate already adopted, skipped", {
151
+ tags: { addonId: job.addonId },
152
+ meta: {
153
+ jobId: job.jobId,
154
+ integrationId: job.integrationId,
155
+ childNativeId
156
+ }
157
+ });
158
+ continue;
159
+ }
160
+ job.currentChildNativeId = childNativeId;
161
+ await this.adoptOne(job, provider, input, childNativeId);
162
+ job.currentChildNativeId = null;
163
+ }
164
+ job.state = job.cancelRequested ? "cancelled" : "done";
165
+ } catch (err) {
166
+ job.state = "failed";
167
+ job.error = require_dist.errMsg(err);
168
+ this.deps.logger.error("adoption job failed", {
169
+ tags: { addonId: job.addonId },
170
+ meta: {
171
+ jobId: job.jobId,
172
+ integrationId: job.integrationId,
173
+ error: job.error
174
+ }
175
+ });
176
+ } finally {
177
+ job.currentChildNativeId = null;
178
+ job.finishedAt = this.now();
179
+ const s = snapshot(job);
180
+ this.deps.logger.info("adoption job finished", {
181
+ tags: { addonId: job.addonId },
182
+ meta: {
183
+ jobId: job.jobId,
184
+ integrationId: job.integrationId,
185
+ state: s.state,
186
+ total: s.total,
187
+ adopted: s.adopted,
188
+ alreadyAdopted: s.alreadyAdopted,
189
+ failed: s.failed,
190
+ accessoriesCreated: s.accessoriesCreated,
191
+ durationMs: (s.finishedAt ?? 0) - s.startedAt
192
+ }
193
+ });
194
+ }
195
+ }
196
+ /**
197
+ * One `listCandidates` snapshot at job start. A read that FAILS must not be
198
+ * read as "nothing is adopted" — that would send every candidate to the
199
+ * provider and turn a safe retry back into a wall of duplicate-stableId
200
+ * errors — so a failure yields an empty set AND a warning, and the
201
+ * per-candidate failure path stays the backstop.
202
+ */
203
+ async alreadyAdopted(provider, input, job) {
204
+ try {
205
+ const page = await provider.listCandidates({
206
+ integrationId: input.integrationId,
207
+ page: 1,
208
+ pageSize: 2e4,
209
+ ...input.filter !== void 0 ? { filter: input.filter } : {}
210
+ });
211
+ const out = /* @__PURE__ */ new Set();
212
+ for (const c of page.candidates) if (c.alreadyAdopted === true) out.add(c.childNativeId);
213
+ return out;
214
+ } catch (err) {
215
+ this.deps.logger.warn("adoption job: pre-flight listCandidates failed — every candidate will be attempted", {
216
+ tags: { addonId: job.addonId },
217
+ meta: {
218
+ jobId: job.jobId,
219
+ integrationId: job.integrationId,
220
+ error: require_dist.errMsg(err)
221
+ }
222
+ });
223
+ return /* @__PURE__ */ new Set();
224
+ }
225
+ }
226
+ async adoptOne(job, provider, input, childNativeId) {
227
+ const startedAt = this.now();
228
+ try {
229
+ const per = input.perCandidate?.[childNativeId];
230
+ const entry = (await provider.adopt({
231
+ integrationId: input.integrationId,
232
+ childNativeIds: [childNativeId],
233
+ ...input.filter !== void 0 ? { filter: input.filter } : {},
234
+ ...input.importLocations !== void 0 ? { importLocations: input.importLocations } : {},
235
+ ...per !== void 0 ? { perCandidate: { [childNativeId]: per } } : {}
236
+ })).adopted[0];
237
+ if (!entry) {
238
+ job.results.push({
239
+ childNativeId,
240
+ outcome: "failed",
241
+ parentDeviceId: null,
242
+ accessoryCount: 0,
243
+ error: "provider returned no adopted entry"
244
+ });
245
+ this.deps.logger.warn("adoption job: provider adopted nothing for candidate", {
246
+ tags: { addonId: job.addonId },
247
+ meta: {
248
+ jobId: job.jobId,
249
+ integrationId: job.integrationId,
250
+ childNativeId
251
+ }
252
+ });
253
+ return;
254
+ }
255
+ job.results.push({
256
+ childNativeId,
257
+ outcome: "adopted",
258
+ parentDeviceId: entry.parentDeviceId,
259
+ accessoryCount: entry.accessoryDeviceIds.length,
260
+ error: null
261
+ });
262
+ this.deps.logger.info("adoption job: candidate adopted", {
263
+ tags: {
264
+ deviceId: entry.parentDeviceId,
265
+ addonId: job.addonId
266
+ },
267
+ meta: {
268
+ jobId: job.jobId,
269
+ integrationId: job.integrationId,
270
+ childNativeId,
271
+ accessories: entry.accessoryDeviceIds.length,
272
+ durationMs: this.now() - startedAt
273
+ }
274
+ });
275
+ } catch (err) {
276
+ job.results.push({
277
+ childNativeId,
278
+ outcome: "failed",
279
+ parentDeviceId: null,
280
+ accessoryCount: 0,
281
+ error: require_dist.errMsg(err)
282
+ });
283
+ this.deps.logger.warn("adoption job: candidate failed", {
284
+ tags: { addonId: job.addonId },
285
+ meta: {
286
+ jobId: job.jobId,
287
+ integrationId: job.integrationId,
288
+ childNativeId,
289
+ durationMs: this.now() - startedAt,
290
+ error: require_dist.errMsg(err)
291
+ }
292
+ });
293
+ }
294
+ }
295
+ };
296
+ //#endregion
9
297
  //#region src/builtins/device-manager/day-night-config-schema.ts
10
298
  var MODE_LABELS = {
11
299
  auto: "Auto",
@@ -1128,6 +1416,27 @@ async function adoptionRelease(pctx, input) {
1128
1416
  const { addonId, ...rest } = input;
1129
1417
  return (await pctx.host.requireDeviceAdoptionProvider(addonId)).release(rest);
1130
1418
  }
1419
+ async function adoptionStartJob(pctx, input) {
1420
+ const { addonId, integrationId, childNativeIds, filter, importLocations, perCandidate } = input;
1421
+ return pctx.host.adoptionJobs.start({
1422
+ addonId,
1423
+ integrationId,
1424
+ childNativeIds,
1425
+ ...filter !== void 0 ? { filter } : {},
1426
+ ...importLocations !== void 0 ? { importLocations } : {},
1427
+ ...perCandidate !== void 0 ? { perCandidate } : {}
1428
+ });
1429
+ }
1430
+ async function adoptionListJobs(pctx, input) {
1431
+ const { addonId, integrationId } = input;
1432
+ return pctx.host.adoptionJobs.list({
1433
+ addonId,
1434
+ ...integrationId !== void 0 ? { integrationId } : {}
1435
+ });
1436
+ }
1437
+ async function adoptionCancelJob(pctx, input) {
1438
+ return { cancelled: pctx.host.adoptionJobs.cancel(input.jobId) };
1439
+ }
1131
1440
  async function adoptionResync(pctx, input) {
1132
1441
  const { camDeviceId, resetToSource } = input;
1133
1442
  let owningAddonId = pctx.registry?.getAddonId(camDeviceId) ?? null;
@@ -3929,6 +4238,8 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
3929
4238
  * the D3 re-handshake after device restore is the reliable replacement.
3930
4239
  */
3931
4240
  remoteNativeCaps = /* @__PURE__ */ new Map();
4241
+ /** Background adoption jobs — lazily constructed (needs `ctx.logger`). */
4242
+ adoptionJobEngine = null;
3932
4243
  /** The runtime-state mirror, asserted present (constructed in onInitialize). */
3933
4244
  get stateMirror() {
3934
4245
  if (!this.stateMirrorImpl) throw new Error("DeviceManagerAddon: state mirror accessed before onInitialize");
@@ -3954,9 +4265,22 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
3954
4265
  resolveDeviceProbed: (deviceId) => this.stateMirror.resolveDeviceProbed(deviceId),
3955
4266
  waitDeviceProvider: (addonId, timeoutMs) => this.waitDeviceProvider(addonId, timeoutMs),
3956
4267
  requireDeviceProvider: (addonId) => this.requireDeviceProvider(addonId),
3957
- requireDeviceAdoptionProvider: (addonId) => this.requireDeviceAdoptionProvider(addonId)
4268
+ requireDeviceAdoptionProvider: (addonId) => this.requireDeviceAdoptionProvider(addonId),
4269
+ adoptionJobs: this.adoptionJobsImpl
3958
4270
  };
3959
4271
  }
4272
+ /**
4273
+ * Background adoption jobs. In-RAM and process-lifetime: a restart forgets
4274
+ * them, which is safe because adoption is keyed by a stable id — re-running a
4275
+ * job re-adopts nothing (see `AdoptionJobEngine`).
4276
+ */
4277
+ get adoptionJobsImpl() {
4278
+ if (!this.adoptionJobEngine) this.adoptionJobEngine = new AdoptionJobEngine({
4279
+ resolveProvider: async (addonId) => this.requireDeviceAdoptionProvider(addonId),
4280
+ logger: this.ctx.logger
4281
+ });
4282
+ return this.adoptionJobEngine;
4283
+ }
3960
4284
  /** Wait for a device-provider by addonId, returning null on timeout. */
3961
4285
  async waitDeviceProvider(addonId, timeoutMs = 5e3) {
3962
4286
  const provider = await this.capabilityRegistry?.waitForProvider("device-provider", addonId, timeoutMs);
@@ -4136,6 +4460,9 @@ var DeviceManagerAddon = class extends require_dist.BaseAddon {
4136
4460
  adoptionRefresh: (input) => adoptionRefresh(pctx, input),
4137
4461
  adoptionAdopt: (input) => adoptionAdopt(pctx, input),
4138
4462
  adoptionRelease: (input) => adoptionRelease(pctx, input),
4463
+ adoptionStartJob: (input) => adoptionStartJob(pctx, input),
4464
+ adoptionListJobs: (input) => adoptionListJobs(pctx, input),
4465
+ adoptionCancelJob: (input) => adoptionCancelJob(pctx, input),
4139
4466
  adoptionResync: (input) => adoptionResync(pctx, input),
4140
4467
  discoveryProviders: async () => {
4141
4468
  return { providers: (await this.listDiscoveryCapableProviderIds()).map((addonId) => ({