@camstack/system 1.2.436 → 1.2.438

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 (96) hide show
  1. package/dist/addon-runner.js +64 -12
  2. package/dist/addon-runner.mjs +65 -13
  3. package/dist/{agent-https-B8lKYVtU.mjs → agent-https-BPfHrI4c.mjs} +3 -3
  4. package/dist/auth/login-session-manager.d.ts +2 -0
  5. package/dist/auth/session-revocation-bus.d.ts +32 -0
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.js +7 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +7 -1
  12. package/dist/builtins/autotrack/index.js +1 -1
  13. package/dist/builtins/autotrack/index.mjs +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  16. package/dist/builtins/calendars/calendars.addon.js +1 -1
  17. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  18. package/dist/builtins/camera-grid/index.js +9 -1
  19. package/dist/builtins/camera-grid/index.mjs +9 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +12 -5
  23. package/dist/builtins/console-logging/index.mjs +12 -5
  24. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  25. package/dist/builtins/core-blocks/core-blocks.addon.mjs +5 -5
  26. package/dist/builtins/device-manager/device-manager.addon.d.ts +5 -0
  27. package/dist/builtins/device-manager/device-manager.addon.js +702 -28
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +702 -28
  29. package/dist/builtins/device-manager/device-meta-types.d.ts +4 -0
  30. package/dist/builtins/device-manager/device-provider-context.d.ts +9 -0
  31. package/dist/builtins/device-manager/device-removal-hooks.d.ts +103 -0
  32. package/dist/builtins/device-manager/device-row-store.d.ts +1 -0
  33. package/dist/builtins/device-manager/device-tombstone-store.d.ts +58 -0
  34. package/dist/builtins/device-manager/removal-cleanup.d.ts +50 -0
  35. package/dist/builtins/hub-forwarder/index.js +1 -1
  36. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  37. package/dist/builtins/keychain/index.js +37 -4
  38. package/dist/builtins/keychain/index.mjs +37 -4
  39. package/dist/builtins/keychain/keychain-service.d.ts +14 -0
  40. package/dist/builtins/keychain/keychain-store.d.ts +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  42. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  43. package/dist/builtins/local-auth/local-auth.addon.js +53 -12
  44. package/dist/builtins/local-auth/local-auth.addon.mjs +53 -13
  45. package/dist/builtins/local-network/local-network.addon.js +10 -1
  46. package/dist/builtins/local-network/local-network.addon.mjs +13 -4
  47. package/dist/builtins/loki-logging/index.js +28 -5
  48. package/dist/builtins/loki-logging/index.mjs +28 -5
  49. package/dist/builtins/native-metrics/native-metrics.addon.js +11 -1
  50. package/dist/builtins/native-metrics/native-metrics.addon.mjs +20 -10
  51. package/dist/builtins/platform-probe/index.js +1 -1
  52. package/dist/builtins/platform-probe/index.mjs +8 -8
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  54. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/snapshot/index.js +11 -1
  56. package/dist/builtins/snapshot/index.mjs +11 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -1
  58. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +4 -1
  59. package/dist/builtins/sqlite-storage/index.js +1 -1
  60. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  61. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
  62. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  64. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  65. package/dist/builtins/system-config/system-config.addon.d.ts +9 -0
  66. package/dist/builtins/system-config/system-config.addon.js +135 -72
  67. package/dist/builtins/system-config/system-config.addon.mjs +135 -73
  68. package/dist/builtins/winston-logging/index.js +14 -5
  69. package/dist/builtins/winston-logging/index.mjs +14 -5
  70. package/dist/{composition-sources-BAOlCu4j.js → composition-sources-DI3Z83vG.js} +1 -1
  71. package/dist/{composition-sources-gN_BWUKp.mjs → composition-sources-DpHGCjdL.mjs} +1 -1
  72. package/dist/{constants-BFpowodq.mjs → constants-DQK705Sb.mjs} +1 -1
  73. package/dist/{constants-GENKqk9k.js → constants-wkcn5Ij3.js} +1 -1
  74. package/dist/{device-ca-CuWuRW9N.js → device-ca-BSvkXqyI.js} +1 -1
  75. package/dist/{device-ca-BNM5ai4t.mjs → device-ca-DvIZjXIl.mjs} +1 -1
  76. package/dist/{dist-DjD2M79P.mjs → dist-Dc8GKC5H.mjs} +301 -6
  77. package/dist/{dist-DVe0Nsp8.js → dist-GgG-7amw.js} +348 -5
  78. package/dist/file-host-worker.js +1 -1
  79. package/dist/file-host-worker.mjs +1 -1
  80. package/dist/{hub-mdns-ciao-DJRwtlA8.mjs → hub-mdns-ciao-DMlQTdPU.mjs} +1 -1
  81. package/dist/i18n/catalog-registry.d.ts +35 -0
  82. package/dist/i18n/index.d.ts +2 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.js +666 -21
  85. package/dist/index.mjs +676 -38
  86. package/dist/kernel/gc-census.d.ts +18 -1
  87. package/dist/kernel/settings-view-types.d.ts +2 -0
  88. package/dist/kernel/transport/local-transport.d.ts +3 -0
  89. package/dist/kernel/transport/peer-answered-error.d.ts +5 -1
  90. package/dist/{restore-archive-D4h904rb.js → restore-archive-CTRz8v9o.js} +1 -1
  91. package/dist/{restore-archive-BxmP1ChO.mjs → restore-archive-DPg9duVY.mjs} +1 -1
  92. package/dist/{retired-settings-keys-CYP5IZJ5.js → retired-settings-keys-Dr_4lfKu.js} +1 -1
  93. package/dist/{retired-settings-keys-CQaknvx1.mjs → retired-settings-keys-Is0zO8gX.mjs} +1 -1
  94. package/dist/{wal-maintenance-CaDsrJM_.mjs → wal-maintenance-Bx3lcVA7.mjs} +0 -0
  95. package/dist/{wal-maintenance-Br60onAQ.js → wal-maintenance-mjB2i-VR.js} +0 -0
  96. package/package.json +1 -1
@@ -718,7 +718,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
718
718
  return EventCategory;
719
719
  }({});
720
720
  //#endregion
721
- //#region ../types/dist/sleep-DAX0-2v9.mjs
721
+ //#region ../types/dist/sleep-DRqxtc0C.mjs
722
722
  /**
723
723
  * The audio chunk plane's byte format, and the ONE expansion from a coded
724
724
  * window to float samples (D455).
@@ -4421,6 +4421,35 @@ function collectZodSecretPaths(schema, prefix = "") {
4421
4421
  return [...new Set(paths)];
4422
4422
  }
4423
4423
  /**
4424
+ * A user-facing error with a STABLE code (D863).
4425
+ *
4426
+ * `message` is always the English text, so every consumer that knows nothing
4427
+ * of codes (old clients, logs, the mesh) behaves exactly as before. The hub's
4428
+ * tRPC error formatter reads `code` + `params` and, when the request language
4429
+ * has a text for `server:<code>`, replaces the response `message`; the code
4430
+ * stays in the payload (`data.i18n`).
4431
+ */
4432
+ /** Dotted lower-case code, e.g. `auth.invalid-credentials`. It is the key in the `server` catalog. */
4433
+ var ErrorCodeSchema = zod.z.string().regex(/^[a-z][a-z0-9-]*(\.[a-z0-9-]+)+$/);
4434
+ zod.z.object({
4435
+ code: ErrorCodeSchema,
4436
+ params: zod.z.record(zod.z.string(), zod.z.union([zod.z.string(), zod.z.number()])).optional()
4437
+ });
4438
+ var CamstackError = class extends Error {
4439
+ i18nCode;
4440
+ i18nParams;
4441
+ constructor(code, params, englishMessage) {
4442
+ super(englishMessage);
4443
+ this.name = "CamstackError";
4444
+ this.i18nCode = code;
4445
+ this.i18nParams = params;
4446
+ }
4447
+ };
4448
+ /** `throw userError('device.not-found', { id }, 'Device 12 not found')` */
4449
+ function userError(code, params, englishFallback) {
4450
+ return new CamstackError(code, params, englishFallback);
4451
+ }
4452
+ /**
4424
4453
  * Type-safe JSON parsing helpers.
4425
4454
  *
4426
4455
  * `JSON.parse` is typed as `any` in lib.es5.d.ts, which triggers
@@ -4486,7 +4515,7 @@ function sleep(ms) {
4486
4515
  return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
4487
4516
  }
4488
4517
  //#endregion
4489
- //#region ../types/dist/err-msg-DX6i_MY4.mjs
4518
+ //#region ../types/dist/err-msg-DLerKiVO.mjs
4490
4519
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
4491
4520
  DeviceType["Camera"] = "camera";
4492
4521
  DeviceType["Hub"] = "hub";
@@ -4736,6 +4765,22 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
4736
4765
  DeviceRole["Nightvision"] = "nightvision";
4737
4766
  DeviceRole["PrivacyMask"] = "privacy-mask";
4738
4767
  DeviceRole["Doorbell"] = "doorbell";
4768
+ /** Interior blind / shade / roller blind. HA `device_class: blind|shade`. */
4769
+ DeviceRole["CoverBlind"] = "cover-blind";
4770
+ /** Exterior roller shutter. HA `device_class: shutter`; Homematic BROLL. */
4771
+ DeviceRole["CoverShutter"] = "cover-shutter";
4772
+ /** Exterior awning. HA `device_class: awning`. */
4773
+ DeviceRole["CoverAwning"] = "cover-awning";
4774
+ /** Curtain / drape. HA `device_class: curtain`. */
4775
+ DeviceRole["CoverCurtain"] = "cover-curtain";
4776
+ /** Garage door. HA `device_class: garage`. A security actuator: exports gate it. */
4777
+ DeviceRole["CoverGarage"] = "cover-garage";
4778
+ /** Gate. HA `device_class: gate`. A security actuator: exports gate it. */
4779
+ DeviceRole["CoverGate"] = "cover-gate";
4780
+ /** Door. HA `device_class: door`. A security actuator: exports gate it. */
4781
+ DeviceRole["CoverDoor"] = "cover-door";
4782
+ /** Window. HA `device_class: window`. */
4783
+ DeviceRole["CoverWindow"] = "cover-window";
4739
4784
  /** Virtual HA toggle (input_boolean.*) — distinguishable from a
4740
4785
  * real Switch device for UI rendering / export adapters. */
4741
4786
  DeviceRole["BinaryHelper"] = "binary-helper";
@@ -4816,7 +4861,7 @@ function errMsg(err) {
4816
4861
  return String(err);
4817
4862
  }
4818
4863
  //#endregion
4819
- //#region ../types/dist/composition-C-WpVYTX.mjs
4864
+ //#region ../types/dist/composition-EQ9Ok0Ee.mjs
4820
4865
  var AUDIO_ENCODER_BY_CODEC = {
4821
4866
  opus: "libopus",
4822
4867
  aac: "aac",
@@ -9769,6 +9814,8 @@ function scopesAllowAddon(scopes, addonId, access) {
9769
9814
  return scopes.some((s) => s.type === "addon" && s.target === addonId && s.access.includes(access));
9770
9815
  }
9771
9816
  zod.z.enum(["new-session", "step-up"]);
9817
+ /** The languages the hub's app landing pages are written in (D858). */
9818
+ var AppPageLangSchema = zod.z.enum(["en", "it"]);
9772
9819
  /** How a native app starts one login method (D858), as `auth.listLoginMethods` reports it. */
9773
9820
  var AppLoginPathSchema = zod.z.discriminatedUnion("kind", [zod.z.object({ kind: zod.z.literal("native") }), zod.z.object({
9774
9821
  kind: zod.z.literal("browser"),
@@ -10371,7 +10418,9 @@ var ConfigTabDeclarationSchema = zod.z.object({
10371
10418
  var ConfigSectionWithValuesSchema = zod.z.object({
10372
10419
  id: zod.z.string(),
10373
10420
  title: zod.z.string(),
10421
+ titleKey: zod.z.string().optional(),
10374
10422
  description: zod.z.string().optional(),
10423
+ descriptionKey: zod.z.string().optional(),
10375
10424
  style: zod.z.enum(["card", "accordion"]).optional(),
10376
10425
  defaultCollapsed: zod.z.boolean().optional(),
10377
10426
  columns: zod.z.union([
@@ -16215,6 +16264,16 @@ var keychainCapability = {
16215
16264
  kind: "mutation",
16216
16265
  auth: "admin"
16217
16266
  }),
16267
+ /**
16268
+ * Delete every value scoped `device/<deviceId>`, whatever its owner (D864).
16269
+ * Reserved to `device-manager`, on the device-removed path: a driver's
16270
+ * device-scoped secret is not anybody's once the device is gone. Answers the
16271
+ * refs removed (never values).
16272
+ */
16273
+ deleteDeviceScope: method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.object({ refs: zod.z.array(zod.z.string()).readonly() }), {
16274
+ kind: "mutation",
16275
+ auth: "admin"
16276
+ }),
16218
16277
  /** The caller's own refs, metadata only. */
16219
16278
  listMeta: method(zod.z.object({}), zod.z.array(KeychainSecretMetaSchema).readonly(), { auth: "admin" }),
16220
16279
  /** Whether values can be served — the save path refuses a write while locked. */
@@ -38219,6 +38278,42 @@ var DeviceRegisterPayloadSchema = zod.z.object({
38219
38278
  * omits it and the keyword backstop applies. */
38220
38279
  secretConfigPaths: zod.z.array(zod.z.string()).optional()
38221
38280
  });
38281
+ /** One deleted device, kept by device-manager so an addon that missed the
38282
+ * deletion can still learn of it (D865). Written by the delete path ONLY. */
38283
+ var DeviceTombstoneSchema = zod.z.object({
38284
+ deviceId: zod.z.number().int().positive(),
38285
+ /** Epoch ms the device was deleted. */
38286
+ deletedAt: zod.z.number(),
38287
+ /** The addon that owned the device when it was deleted. */
38288
+ providerAddonId: zod.z.string()
38289
+ });
38290
+ /** How long a tombstone stays readable. Past it, a device that was deleted
38291
+ * and never cleaned is only reachable by the admin "clean data of deleted
38292
+ * devices" action. */
38293
+ var DEVICE_TOMBSTONE_RETENTION_MS = 2160 * 60 * 60 * 1e3;
38294
+ /** Data held for one device that device-manager no longer knows. */
38295
+ var OrphanDeviceDataSchema = zod.z.object({
38296
+ deviceId: zod.z.number().int().positive(),
38297
+ /** Rows/files per store (`<addonId>:<store>`). */
38298
+ stores: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative())
38299
+ });
38300
+ var CleanupDeletedDevicesResultSchema = zod.z.object({
38301
+ /**
38302
+ * `skipped` — the absence check could not be trusted (a device-list read
38303
+ * failed or the two reads disagreed); nothing was listed or deleted.
38304
+ * `dry-run` — `devices` is what a confirmed run would delete.
38305
+ * `cleaned` — `devices` is what was deleted.
38306
+ */
38307
+ status: zod.z.enum([
38308
+ "skipped",
38309
+ "dry-run",
38310
+ "cleaned"
38311
+ ]),
38312
+ reason: zod.z.string().nullable(),
38313
+ devices: zod.z.array(OrphanDeviceDataSchema),
38314
+ /** Implementers that could not be asked (their stores are not in `devices`). */
38315
+ unreachable: zod.z.array(zod.z.string())
38316
+ });
38222
38317
  var DeviceRemovePayloadSchema = zod.z.object({ deviceId: zod.z.number() });
38223
38318
  var DevicePersistConfigPayloadSchema = zod.z.object({
38224
38319
  deviceId: zod.z.number(),
@@ -38815,6 +38910,27 @@ var deviceManagerCapability = {
38815
38910
  kind: "mutation",
38816
38911
  auth: "admin"
38817
38912
  }),
38913
+ /**
38914
+ * The tombstones of devices deleted at or after `sinceMs` (D865). The
38915
+ * reconcile feed of every `device-removal-hook` implementer: an addon that
38916
+ * was down when a device was deleted asks here at start and periodically.
38917
+ * A tombstone exists only for a DELETE — never for a device that is merely
38918
+ * unregistered, offline or whose provider is restarting. Tombstones older
38919
+ * than `DEVICE_TOMBSTONE_RETENTION_MS` are gone.
38920
+ */
38921
+ listDeletedSince: method(zod.z.object({ sinceMs: zod.z.number() }), zod.z.array(DeviceTombstoneSchema).readonly(), { auth: "admin" }),
38922
+ /**
38923
+ * Admin-triggered clean-up of data that belongs to devices deleted BEFORE
38924
+ * tombstones existed (D865). Asks every `device-removal-hook` implementer
38925
+ * which device ids it holds data for, keeps those absent from the device
38926
+ * list — confirmed by TWO reads of the list, skipped if either fails — and
38927
+ * with `confirm: false` only reports the counts per store. `confirm: true`
38928
+ * deletes. Never runs on its own.
38929
+ */
38930
+ cleanupDeletedDevicesData: method(zod.z.object({ confirm: zod.z.boolean() }), CleanupDeletedDevicesResultSchema, {
38931
+ kind: "mutation",
38932
+ auth: "admin"
38933
+ }),
38818
38934
  /** Cascade-delete every top-level device whose `integrationId` matches.
38819
38935
  * Children cascade automatically via the per-parent remove path.
38820
38936
  * Idempotent: a device whose `integrationId` was never set never matches.
@@ -39730,6 +39846,85 @@ var embeddingEncoderCapability = {
39730
39846
  }
39731
39847
  };
39732
39848
  /**
39849
+ * `device-removal-hook` — the reliable way an addon learns a device was DELETED,
39850
+ * so it can delete what it keeps for that device (D865).
39851
+ *
39852
+ * ## Why an event was not enough
39853
+ *
39854
+ * `DeviceUnregistered` is telemetry and may be dropped (D8, D11). An addon that
39855
+ * hung its per-device clean-up on it left durable garbage whenever the event was
39856
+ * lost, the addon was down, or it was restarting at that moment — footage,
39857
+ * analytics rows and settings of device 4483 outlived the device. Loss of this
39858
+ * signal corrupts durable state, so it travels by RPC with a recorded fact
39859
+ * behind it (D8: "if loss would corrupt durable state, use RPC plus a reconcile").
39860
+ *
39861
+ * ## The three pieces
39862
+ *
39863
+ * 1. device-manager records a TOMBSTONE per deleted device
39864
+ * (`deviceManager.listDeletedSince`). The tombstone is written by the delete
39865
+ * path only — a device that is unregistered, offline or whose provider is
39866
+ * restarting is NOT deleted and gets none.
39867
+ * 2. After a delete, device-manager calls `onDeviceRemoved` on EVERY provider of
39868
+ * this collection, one by one, with bounded retries, logged.
39869
+ * 3. An implementer that was down asks `deviceManager.listDeletedSince` at start
39870
+ * (and periodically) and runs its own `onDeviceRemoved` for each tombstone it
39871
+ * may have missed. Reconcile is driven by tombstones, never by "the device is
39872
+ * not in the current list": a failed or partial list read must not destroy data.
39873
+ *
39874
+ * ## Contract for an implementer
39875
+ *
39876
+ * - **Idempotent.** It is called again by a retry, by a reconcile and by the
39877
+ * admin cleanup of data that predates tombstones. A device with nothing left
39878
+ * answers zero counts.
39879
+ * - **One key per store** in `counts`, deleted rows/files per store, so the log
39880
+ * line and the admin dry run can say where the data was.
39881
+ * - **Training datasets are NOT device data** and are never deleted by a hook.
39882
+ * - **Per-device SETTINGS are not hooked.** Configuration lives in the standard
39883
+ * per-device store (`ctx.settings.*DeviceStore`), which device-manager clears
39884
+ * for every addon centrally at delete time. This hook is for device DATA
39885
+ * that is not settings: footage, event media, analytics rows, history.
39886
+ * - A provider that cannot tell is allowed to throw; the caller retries it.
39887
+ *
39888
+ * `listDeviceData` is the read side of the admin "Clean data of deleted devices"
39889
+ * action: which device ids this addon holds data for, and how much per store. It
39890
+ * never deletes. device-manager decides which of those ids are absent from the
39891
+ * fleet, from TWO consistent reads of the device list (D49).
39892
+ */
39893
+ /** What a hook is told about the deletion. */
39894
+ var DeviceRemovedInputSchema = zod.z.object({
39895
+ deviceId: zod.z.number().int().positive(),
39896
+ /** Epoch ms the device was deleted (the tombstone's `deletedAt`). */
39897
+ deletedAt: zod.z.number(),
39898
+ /** The addon that owned the device, as device-manager last knew it. */
39899
+ providerAddonId: zod.z.string()
39900
+ });
39901
+ /** Rows/files/refs deleted, per store this implementer owns. */
39902
+ var DeviceRemovedResultSchema = zod.z.object({ counts: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()) });
39903
+ /** One (store, device) pair an implementer holds data for. */
39904
+ var DeviceDataEntrySchema = zod.z.object({
39905
+ store: zod.z.string(),
39906
+ deviceId: zod.z.number().int().positive(),
39907
+ /** Rows (or files) held for the device in the store. */
39908
+ count: zod.z.number().int().nonnegative()
39909
+ });
39910
+ var deviceRemovalHookCapability = {
39911
+ name: "device-removal-hook",
39912
+ scope: "system",
39913
+ mode: "collection",
39914
+ internal: true,
39915
+ methods: {
39916
+ /** Delete everything this addon keeps for the deleted device. Idempotent. */
39917
+ onDeviceRemoved: method(DeviceRemovedInputSchema, DeviceRemovedResultSchema, {
39918
+ kind: "mutation",
39919
+ auth: "admin"
39920
+ }),
39921
+ /** Which devices this addon holds data for, per store. Reads only. */
39922
+ listDeviceData: method(zod.z.void(), zod.z.array(DeviceDataEntrySchema).readonly(), { auth: "admin" })
39923
+ },
39924
+ /** In-process only — enumerated through `addons.listCapabilityProviders`. */
39925
+ mount: { kind: "skip" }
39926
+ };
39927
+ /**
39733
39928
  * `failure-contribution` — the capability an addon reports its OWN losses
39734
39929
  * through, per camera, with the denominator attached. It stores nothing.
39735
39930
  *
@@ -54193,7 +54388,9 @@ var SsoBridgeClaimsSchema = zod.z.object({
54193
54388
  codeChallenge: zod.z.string(),
54194
54389
  state: zod.z.string(),
54195
54390
  purpose: zod.z.enum(["new-session", "step-up"]),
54196
- redirect: zod.z.string()
54391
+ redirect: zod.z.string(),
54392
+ /** The page language the app asked for (D858); the confirm page speaks it. */
54393
+ lang: zod.z.enum(["en", "it"]).optional()
54197
54394
  }).optional()
54198
54395
  });
54199
54396
  var ssoBridgeCapability = {
@@ -68642,6 +68839,37 @@ var switchCapability = {
68642
68839
  }
68643
68840
  }] }
68644
68841
  };
68842
+ /** C0 controls, DEL and the C1 range: none of them belongs in a name. */
68843
+ function hasControlCharacter(value) {
68844
+ for (const char of value) {
68845
+ const code = char.codePointAt(0) ?? 0;
68846
+ if (code <= 31 || code >= 127 && code <= 159) return true;
68847
+ }
68848
+ return false;
68849
+ }
68850
+ /** A name an operator may save: trimmed, 1-48 characters, no control characters. */
68851
+ var ServerNameSchema = zod.z.string().transform((value) => value.trim()).pipe(zod.z.string().min(1, "The server name cannot be empty").max(48, `The server name is at most 48 characters`).refine((value) => !hasControlCharacter(value), { message: "The server name cannot contain control characters" }));
68852
+ /** What every reader gets: the name to show, and whether the hub chose it itself. */
68853
+ var ServerNameInfoSchema = zod.z.object({
68854
+ name: zod.z.string(),
68855
+ /** `true` when nobody named the hub: `name` is the machine hostname. */
68856
+ isDefault: zod.z.boolean()
68857
+ });
68858
+ /** What an unset name shows when the hostname says nothing about the hub. */
68859
+ var SERVER_NAME_FALLBACK = "CamStack";
68860
+ /** A container id: Docker's default hostname (12 hex chars, or the full 64). */
68861
+ var CONTAINER_ID_PATTERN = /^(?:[0-9a-f]{12}|[0-9a-f]{64})$/;
68862
+ /**
68863
+ * The hostname without its domain (`nas.lan.example` becomes `nas`). A hostname
68864
+ * that names nothing (empty, `localhost`, a container id) yields
68865
+ * {@link SERVER_NAME_FALLBACK}.
68866
+ */
68867
+ function shortHostname(hostname) {
68868
+ const first = hostname.trim().split(".")[0] ?? "";
68869
+ if (first.length === 0 || first.toLowerCase() === "localhost") return SERVER_NAME_FALLBACK;
68870
+ if (CONTAINER_ID_PATTERN.test(first)) return SERVER_NAME_FALLBACK;
68871
+ return first;
68872
+ }
68645
68873
  /**
68646
68874
  * system — system-scoped singleton capability exposing hub-level
68647
68875
  * health, feature flags, network interface enumeration, and the
@@ -68671,6 +68899,12 @@ var FeatureManifestSchema = zod.z.object({
68671
68899
  backup: zod.z.boolean(),
68672
68900
  repl: zod.z.boolean()
68673
68901
  });
68902
+ /**
68903
+ * `system.info`: the feature flags plus the hub's human name (D861). The name is
68904
+ * `{ name, isDefault }` — `isDefault: true` means nobody named the hub and `name`
68905
+ * is the machine hostname.
68906
+ */
68907
+ var SystemInfoSchema = FeatureManifestSchema.extend({ serverName: ServerNameInfoSchema });
68674
68908
  var HealthStatusSchema = zod.z.object({
68675
68909
  status: zod.z.literal("ok"),
68676
68910
  uptime: zod.z.number()
@@ -69157,7 +69391,7 @@ var systemCapability = {
69157
69391
  scope: "system",
69158
69392
  mode: "singleton",
69159
69393
  methods: {
69160
- info: method(zod.z.void(), FeatureManifestSchema),
69394
+ info: method(zod.z.void(), SystemInfoSchema),
69161
69395
  health: method(zod.z.void(), HealthStatusSchema),
69162
69396
  featureFlags: method(zod.z.void(), FeatureManifestSchema),
69163
69397
  networkAddresses: method(zod.z.void(), zod.z.array(NetworkAddressSchema).readonly()),
@@ -74760,6 +74994,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
74760
74994
  addonId: null,
74761
74995
  access: "create"
74762
74996
  },
74997
+ "deviceManager.cleanupDeletedDevicesData": {
74998
+ capName: "device-manager",
74999
+ capScope: "system",
75000
+ addonId: null,
75001
+ access: "create"
75002
+ },
74763
75003
  "deviceManager.createDevice": {
74764
75004
  capName: "device-manager",
74765
75005
  capScope: "system",
@@ -74940,6 +75180,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
74940
75180
  addonId: null,
74941
75181
  access: "view"
74942
75182
  },
75183
+ "deviceManager.listDeletedSince": {
75184
+ capName: "device-manager",
75185
+ capScope: "system",
75186
+ addonId: null,
75187
+ access: "view"
75188
+ },
74943
75189
  "deviceManager.listDeviceIdsByCaps": {
74944
75190
  capName: "device-manager",
74945
75191
  capScope: "system",
@@ -75348,6 +75594,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
75348
75594
  addonId: null,
75349
75595
  access: "create"
75350
75596
  },
75597
+ "deviceRemovalHook.listDeviceData": {
75598
+ capName: "device-removal-hook",
75599
+ capScope: "system",
75600
+ addonId: null,
75601
+ access: "view"
75602
+ },
75603
+ "deviceRemovalHook.onDeviceRemoved": {
75604
+ capName: "device-removal-hook",
75605
+ capScope: "system",
75606
+ addonId: null,
75607
+ access: "create"
75608
+ },
75351
75609
  "deviceState.claimFields": {
75352
75610
  capName: "device-state",
75353
75611
  capScope: "system",
@@ -75780,6 +76038,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
75780
76038
  addonId: null,
75781
76039
  access: "delete"
75782
76040
  },
76041
+ "keychain.deleteDeviceScope": {
76042
+ capName: "keychain",
76043
+ capScope: "system",
76044
+ addonId: null,
76045
+ access: "delete"
76046
+ },
75783
76047
  "keychain.getState": {
75784
76048
  capName: "keychain",
75785
76049
  capScope: "system",
@@ -81162,6 +81426,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
81162
81426
  deviceManagerCapability,
81163
81427
  deviceOpsCapability,
81164
81428
  deviceProviderCapability,
81429
+ deviceRemovalHookCapability,
81165
81430
  deviceStateCapability,
81166
81431
  deviceStatusCapability,
81167
81432
  doorbellCapability,
@@ -82055,6 +82320,11 @@ Object.freeze({
82055
82320
  form: "single",
82056
82321
  optional: false
82057
82322
  }],
82323
+ "deviceRemovalHook.onDeviceRemoved": [{
82324
+ name: "deviceId",
82325
+ form: "single",
82326
+ optional: false
82327
+ }],
82058
82328
  "deviceState.claimFields": [{
82059
82329
  name: "deviceId",
82060
82330
  form: "single",
@@ -82244,6 +82514,11 @@ Object.freeze({
82244
82514
  form: "single",
82245
82515
  optional: false
82246
82516
  }],
82517
+ "keychain.deleteDeviceScope": [{
82518
+ name: "deviceId",
82519
+ form: "single",
82520
+ optional: false
82521
+ }],
82247
82522
  "lawnMowerControl.dock": [{
82248
82523
  name: "deviceId",
82249
82524
  form: "single",
@@ -84892,6 +85167,26 @@ new Set([
84892
85167
  "audio-tools",
84893
85168
  "audio-silence"
84894
85169
  ]);
85170
+ var CATALOG_LANGS = AppPageLangSchema.options;
85171
+ /** One catalog file: flat key to text. A file of any other shape is rejected whole. */
85172
+ var CatalogFileSchema = zod.z.record(zod.z.string().min(1), zod.z.string());
85173
+ /** Fills `{name}` placeholders; an unknown placeholder is left as written. */
85174
+ function interpolate(template, params) {
85175
+ if (params === void 0) return template;
85176
+ return template.replace(/\{(\w+)\}/g, (whole, name) => {
85177
+ const value = params[name];
85178
+ return value === void 0 ? whole : String(value);
85179
+ });
85180
+ }
85181
+ /** Splits `"ns:key"`; `null` when the reference has no namespace. */
85182
+ function splitTranslationRef(ref) {
85183
+ const at = ref.indexOf(":");
85184
+ if (at <= 0 || at === ref.length - 1) return null;
85185
+ return {
85186
+ ns: ref.slice(0, at),
85187
+ key: ref.slice(at + 1)
85188
+ };
85189
+ }
84895
85190
  /**
84896
85191
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
84897
85192
  *
@@ -85649,6 +85944,12 @@ Object.defineProperty(exports, "CAP_NAMES_WITH_STATUS", {
85649
85944
  return CAP_NAMES_WITH_STATUS;
85650
85945
  }
85651
85946
  });
85947
+ Object.defineProperty(exports, "CATALOG_LANGS", {
85948
+ enumerable: true,
85949
+ get: function() {
85950
+ return CATALOG_LANGS;
85951
+ }
85952
+ });
85652
85953
  Object.defineProperty(exports, "COMPOSED_ITEM_FIXED_FIELDS", {
85653
85954
  enumerable: true,
85654
85955
  get: function() {
@@ -85685,6 +85986,12 @@ Object.defineProperty(exports, "CalendarPreferencesSchema", {
85685
85986
  return CalendarPreferencesSchema;
85686
85987
  }
85687
85988
  });
85989
+ Object.defineProperty(exports, "CatalogFileSchema", {
85990
+ enumerable: true,
85991
+ get: function() {
85992
+ return CatalogFileSchema;
85993
+ }
85994
+ });
85688
85995
  Object.defineProperty(exports, "CoreBlockSchema", {
85689
85996
  enumerable: true,
85690
85997
  get: function() {
@@ -85769,6 +86076,12 @@ Object.defineProperty(exports, "DEVICE_STATUS_METHOD", {
85769
86076
  return DEVICE_STATUS_METHOD;
85770
86077
  }
85771
86078
  });
86079
+ Object.defineProperty(exports, "DEVICE_TOMBSTONE_RETENTION_MS", {
86080
+ enumerable: true,
86081
+ get: function() {
86082
+ return DEVICE_TOMBSTONE_RETENTION_MS;
86083
+ }
86084
+ });
85772
86085
  Object.defineProperty(exports, "DeclaredDevices", {
85773
86086
  enumerable: true,
85774
86087
  get: function() {
@@ -85937,6 +86250,12 @@ Object.defineProperty(exports, "ScopedTokenSchema", {
85937
86250
  return ScopedTokenSchema;
85938
86251
  }
85939
86252
  });
86253
+ Object.defineProperty(exports, "ServerNameSchema", {
86254
+ enumerable: true,
86255
+ get: function() {
86256
+ return ServerNameSchema;
86257
+ }
86258
+ });
85940
86259
  Object.defineProperty(exports, "SsoBridgeClaimsSchema", {
85941
86260
  enumerable: true,
85942
86261
  get: function() {
@@ -86429,6 +86748,12 @@ Object.defineProperty(exports, "hydrateSchema", {
86429
86748
  return hydrateSchema;
86430
86749
  }
86431
86750
  });
86751
+ Object.defineProperty(exports, "interpolate", {
86752
+ enumerable: true,
86753
+ get: function() {
86754
+ return interpolate;
86755
+ }
86756
+ });
86432
86757
  Object.defineProperty(exports, "isAppLinkBase", {
86433
86758
  enumerable: true,
86434
86759
  get: function() {
@@ -86819,6 +87144,12 @@ Object.defineProperty(exports, "settingsStoreCapability", {
86819
87144
  return settingsStoreCapability;
86820
87145
  }
86821
87146
  });
87147
+ Object.defineProperty(exports, "shortHostname", {
87148
+ enumerable: true,
87149
+ get: function() {
87150
+ return shortHostname;
87151
+ }
87152
+ });
86822
87153
  Object.defineProperty(exports, "siteZoneKey", {
86823
87154
  enumerable: true,
86824
87155
  get: function() {
@@ -86837,6 +87168,12 @@ Object.defineProperty(exports, "snapshotCapability", {
86837
87168
  return snapshotCapability;
86838
87169
  }
86839
87170
  });
87171
+ Object.defineProperty(exports, "splitTranslationRef", {
87172
+ enumerable: true,
87173
+ get: function() {
87174
+ return splitTranslationRef;
87175
+ }
87176
+ });
86840
87177
  Object.defineProperty(exports, "storageCapability", {
86841
87178
  enumerable: true,
86842
87179
  get: function() {
@@ -86903,6 +87240,12 @@ Object.defineProperty(exports, "transformSecretWrite", {
86903
87240
  return transformSecretWrite;
86904
87241
  }
86905
87242
  });
87243
+ Object.defineProperty(exports, "userError", {
87244
+ enumerable: true,
87245
+ get: function() {
87246
+ return userError;
87247
+ }
87248
+ });
86906
87249
  Object.defineProperty(exports, "userManagementCapability", {
86907
87250
  enumerable: true,
86908
87251
  get: function() {
@@ -1,5 +1,5 @@
1
1
  require("./chunk-Cek0wNdY.js");
2
- const require_wal_maintenance = require("./wal-maintenance-Br60onAQ.js");
2
+ const require_wal_maintenance = require("./wal-maintenance-mjB2i-VR.js");
3
3
  let node_worker_threads = require("node:worker_threads");
4
4
  //#region src/builtins/sqlite-storage/file-host-worker.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { C as callControl, E as controlTargetOf, T as callVector, _ as collectTransferables, a as WalMaintenance, b as isFileHostWorkerData, c as SqliteSettingsBackend, h as serializeError, o as createVectorIndex, s as vectorProviderOf, w as callData, x as trustInput, y as isFileHostRequest } from "./wal-maintenance-CaDsrJM_.mjs";
1
+ import { C as callControl, E as controlTargetOf, T as callVector, _ as collectTransferables, a as WalMaintenance, b as isFileHostWorkerData, c as SqliteSettingsBackend, h as serializeError, o as createVectorIndex, s as vectorProviderOf, w as callData, x as trustInput, y as isFileHostRequest } from "./wal-maintenance-Bx3lcVA7.mjs";
2
2
  import { parentPort, threadId, workerData } from "node:worker_threads";
3
3
  //#region src/builtins/sqlite-storage/file-host-worker.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "./chunk-CNf5ZN-e.mjs";
2
- import { D as reasonRequiresNewCa, E as evaluateExistingCert, _ as generateCa, b as collectCertIdentity, v as issueLeaf, y as loadCa } from "./agent-https-B8lKYVtU.mjs";
2
+ import { D as reasonRequiresNewCa, E as evaluateExistingCert, _ as generateCa, b as collectCertIdentity, v as issueLeaf, y as loadCa } from "./agent-https-BPfHrI4c.mjs";
3
3
  import { X509Certificate, createPrivateKey } from "node:crypto";
4
4
  import { writeOwnerOnlyFileSync } from "@camstack/types/node";
5
5
  import { mkdir, writeFile } from "node:fs/promises";
@@ -0,0 +1,35 @@
1
+ import { type CatalogLang, type CatalogLookup, type TranslationParams } from "@camstack/types";
2
+ /** The core namespace: user-facing error texts and core schema labels. */
3
+ export declare const SERVER_NAMESPACE = "server";
4
+ /** `@camstack/addon-provider-reolink` -> `provider-reolink`; `@camstack/system` -> `system`. */
5
+ export declare function catalogNamespaceOf(packageName: string): string;
6
+ export type CatalogWarn = (message: string) => void;
7
+ export declare class CatalogRegistry {
8
+ private readonly warn;
9
+ private readonly namespaces;
10
+ constructor(warn?: CatalogWarn);
11
+ /** Validates `raw` and installs it; returns false (after warning) when it is not a flat string map. */
12
+ set(ns: string, lang: CatalogLang, raw: unknown, origin: string): boolean;
13
+ /** Loads `<packageDir>/i18n/<lang>.json` for every language that has a file. */
14
+ loadAddonDir(ns: string, packageDir: string): void;
15
+ /** Drops a namespace (addon uninstalled or redeployed before a reload). */
16
+ clear(ns: string): void;
17
+ /** The text for `ns:key` in `lang`, or `undefined`. Never falls back across languages. */
18
+ lookup(lang: CatalogLang, ns: string, key: string): string | undefined;
19
+ /**
20
+ * `t(ns, key, params, fallbackEnglish)` - the translation in `lang`, else
21
+ * the English fallback (also interpolated). English is never looked up: the
22
+ * fallback IS the English text.
23
+ */
24
+ t(lang: CatalogLang, ns: string, key: string, params: TranslationParams | undefined, fallbackEnglish: string): string;
25
+ /** A lookup bound to one language, for `localizeConfigTree`. English never substitutes. */
26
+ lookupFor(lang: CatalogLang): CatalogLookup;
27
+ /** `t` for a `"ns:key"` reference. */
28
+ tRef(lang: CatalogLang, ref: string, params: TranslationParams | undefined, fallbackEnglish: string): string;
29
+ }
30
+ /** A fresh registry holding the core `server` namespace (specs build their own). */
31
+ export declare function createCoreCatalogRegistry(warn?: CatalogWarn): CatalogRegistry;
32
+ /** The hub's one registry, core catalogs preloaded. */
33
+ export declare function getCatalogRegistry(warn?: CatalogWarn): CatalogRegistry;
34
+ /** Spec hook: forget the shared registry. */
35
+ export declare function resetCatalogRegistryForTests(): void;
@@ -0,0 +1,2 @@
1
+ export { catalogNamespaceOf, CatalogRegistry, createCoreCatalogRegistry, getCatalogRegistry, resetCatalogRegistryForTests, SERVER_NAMESPACE } from "./catalog-registry.js";
2
+ export type { CatalogWarn } from "./catalog-registry.js";
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export type { TokenExpiryResult } from "./auth/token-expiry.js";
14
14
  export { parseTokenExpiry } from "./auth/token-expiry.js";
15
15
  export type { CreateLoginSessionInput, LoginSessionCheck, LoginSessionMethod, LoginSessionRecord, LoginSessionRefresh, LoginSessionRevocation, LoginSessionSummary } from "./auth/login-session-manager.js";
16
16
  export { LoginSessionManager, REFRESH_TOKEN_PREFIX } from "./auth/login-session-manager.js";
17
+ export { onSessionsRevoked } from "./auth/session-revocation-bus.js";
18
+ export type { SessionsRevokedEvent, SessionsRevokedListener } from "./auth/session-revocation-bus.js";
17
19
  export type { AdminTokenRecord } from "./auth/admin-token-manager.js";
18
20
  export { ADMIN_TOKEN_MAX_LIFETIME_MS, ADMIN_TOKEN_PREFIX, AdminTokenManager } from "./auth/admin-token-manager.js";
19
21
  export { DeviceCaStore } from "./auth/device-ca-store.js";
@@ -143,3 +145,4 @@ export { CAP_METHOD_NOT_IMPLEMENTED } from "./kernel/moleculer/child-cap-dispatc
143
145
  export { BackupDecryptError, BackupKeyFormatError, BackupKeyMismatchError, generateBackupKeyPair, readBackupEncryptionHeader } from "./builtins/system-backup/backup-encryption.js";
144
146
  export { SystemBackupService } from "./builtins/system-backup/system-backup.service.js";
145
147
  export { BackupKeyRequiredError, prepareRestoreArchive } from "./builtins/backup-orchestrator/restore-archive.js";
148
+ export * from "./i18n/index.js";