@camstack/system 1.2.90 → 1.2.92
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 +25 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +25 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/blocks-integration.d.ts +34 -1
- package/dist/builtins/core-blocks/core-block-store.d.ts +11 -0
- package/dist/builtins/core-blocks/core-blocks.addon.js +80 -22
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +80 -22
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- 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/auth-schema.d.ts +42 -0
- package/dist/builtins/local-auth/local-auth.addon.js +43 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +43 -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 +16 -5
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +16 -5
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +19 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +19 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +12 -0
- 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-CYqL8oZq.js → dist-BH2tZ9ZN.js} +525 -47
- package/dist/{dist-DMhxx5Kr.mjs → dist-DXDvrBi0.mjs} +525 -47
- package/dist/index.js +78 -6
- package/dist/index.mjs +78 -6
- package/dist/kernel/addon-health-monitor.d.ts +10 -1
- package/dist/logging/log-manager.d.ts +28 -0
- package/dist/{manifest-python-deps-C0zkl1Ae.js → manifest-python-deps-BZO_eMn-.js} +1 -7
- package/dist/{manifest-python-deps-fWzdEasI.mjs → manifest-python-deps-D3hP9W8D.mjs} +2 -8
- package/package.json +1 -1
package/dist/addon-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_manifest_python_deps = require("./manifest-python-deps-
|
|
2
|
+
const require_manifest_python_deps = require("./manifest-python-deps-BZO_eMn-.js");
|
|
3
3
|
const require_custom_action_registry = require("./custom-action-registry-jY0NOZK8.js");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
node_path = require_chunk.__toESM(node_path);
|
package/dist/addon-runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, xt as resolveAddonClass } from "./manifest-python-deps-
|
|
1
|
+
import { I as createUdsLoggerWithControl, L as LocalChildClient, at as setWorkerNativeCapsChangeListener, bt as installManifestNativeDeps, i as createUdsAddonContext, nt as getWorkerNativeCapProvider, rt as getWorkerNativeCapSnapshot, st as validateProviderRegistrations, t as installManifestPythonDeps, xt as resolveAddonClass } from "./manifest-python-deps-D3hP9W8D.mjs";
|
|
2
2
|
import { t as CustomActionRegistry } from "./custom-action-registry-F__gp_VX.mjs";
|
|
3
3
|
import { register } from "node:module";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ut as EventCategory, _t as BaseAddon, gt as errMsg, v as addonPagesCapability } from "../../dist-
|
|
1
|
+
import { Ut as EventCategory, _t as BaseAddon, gt as errMsg, v as addonPagesCapability } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ut as EventCategory, _t as BaseAddon, b as addonWidgetsCapability, gt as errMsg } from "../../dist-
|
|
1
|
+
import { Ut as EventCategory, _t as BaseAddon, b as addonWidgetsCapability, gt as errMsg } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
//#region src/builtins/alerts/prune-policy.ts
|
|
8
8
|
/**
|
|
9
9
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg, n as AlertSchema, x as alertsCapability } from "../../dist-
|
|
1
|
+
import { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg, n as AlertSchema, x as alertsCapability } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
//#region src/builtins/alerts/prune-policy.ts
|
|
3
3
|
/**
|
|
4
4
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let buffer = require("buffer");
|
|
9
9
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -4204,6 +4204,18 @@ function previewNextRuns(cron, count, after) {
|
|
|
4204
4204
|
}
|
|
4205
4205
|
//#endregion
|
|
4206
4206
|
//#region src/builtins/backup-orchestrator/destination-policy.ts
|
|
4207
|
+
/**
|
|
4208
|
+
* @durable class=config owner=backup-orchestrator
|
|
4209
|
+
* write="`ensureDefault` auto-creates one row the first time a `backups` storage
|
|
4210
|
+
* location is listed (enabled, retentionCount 7, cron `0 3 * * *`), and an operator
|
|
4211
|
+
* edit rewrites it (`upsert` = delete + insert, carrying `last_run_at` forward so a
|
|
4212
|
+
* label change does not reset the schedule baseline)"
|
|
4213
|
+
* retention="none — `delete(locationId)` exists but NOTHING calls it, so a policy row
|
|
4214
|
+
* outlives the `StorageLocation` it names and the table only ever grows, by one row
|
|
4215
|
+
* per backups location ever seen. Losing a row is recoverable: the next
|
|
4216
|
+
* `listDestinations` pass re-creates it from the defaults, which silently discards
|
|
4217
|
+
* the operator's own retention count and cron."
|
|
4218
|
+
*/
|
|
4207
4219
|
var BACKUP_DESTINATION_POLICIES = "backup_destination_policies";
|
|
4208
4220
|
var BACKUP_DESTINATION_POLICIES_COLUMNS = [
|
|
4209
4221
|
{
|
|
@@ -4590,6 +4602,18 @@ var LocationManifestLock = class {
|
|
|
4590
4602
|
};
|
|
4591
4603
|
//#endregion
|
|
4592
4604
|
//#region src/builtins/backup-orchestrator/schedule-store.ts
|
|
4605
|
+
/**
|
|
4606
|
+
* @durable class=config owner=backup-orchestrator
|
|
4607
|
+
* write="an operator creating or editing a schedule (`upsert`, implemented as
|
|
4608
|
+
* delete + insert: cron, enabled, the fan-out `location_ids`, `retention_count`,
|
|
4609
|
+
* optional `data_sources`), plus a `last_run_at` stamp the orchestrator writes on
|
|
4610
|
+
* every due tick BEFORE the archive runs, so an upload outliving the tick cannot
|
|
4611
|
+
* fire the same schedule twice"
|
|
4612
|
+
* retention="only the operator's `delete(id)` — no sweep, no expiry, and `retention_count`
|
|
4613
|
+
* bounds the ARCHIVES at the destination, never these rows. Losing the table stops
|
|
4614
|
+
* every scheduled backup silently: no cron remains to fire, and the fan-out sets and
|
|
4615
|
+
* retention counts are gone with it."
|
|
4616
|
+
*/
|
|
4593
4617
|
var BACKUP_SCHEDULES = "backup_schedules";
|
|
4594
4618
|
var BACKUP_SCHEDULES_COLUMNS = [
|
|
4595
4619
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as backupCapability, Ut as EventCategory, _t as BaseAddon } from "../../dist-
|
|
1
|
+
import { C as backupCapability, Ut as EventCategory, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
3
3
|
import { Buffer as Buffer$1 } from "buffer";
|
|
4
4
|
import * as fsp from "node:fs/promises";
|
|
@@ -4189,6 +4189,18 @@ function previewNextRuns(cron, count, after) {
|
|
|
4189
4189
|
}
|
|
4190
4190
|
//#endregion
|
|
4191
4191
|
//#region src/builtins/backup-orchestrator/destination-policy.ts
|
|
4192
|
+
/**
|
|
4193
|
+
* @durable class=config owner=backup-orchestrator
|
|
4194
|
+
* write="`ensureDefault` auto-creates one row the first time a `backups` storage
|
|
4195
|
+
* location is listed (enabled, retentionCount 7, cron `0 3 * * *`), and an operator
|
|
4196
|
+
* edit rewrites it (`upsert` = delete + insert, carrying `last_run_at` forward so a
|
|
4197
|
+
* label change does not reset the schedule baseline)"
|
|
4198
|
+
* retention="none — `delete(locationId)` exists but NOTHING calls it, so a policy row
|
|
4199
|
+
* outlives the `StorageLocation` it names and the table only ever grows, by one row
|
|
4200
|
+
* per backups location ever seen. Losing a row is recoverable: the next
|
|
4201
|
+
* `listDestinations` pass re-creates it from the defaults, which silently discards
|
|
4202
|
+
* the operator's own retention count and cron."
|
|
4203
|
+
*/
|
|
4192
4204
|
var BACKUP_DESTINATION_POLICIES = "backup_destination_policies";
|
|
4193
4205
|
var BACKUP_DESTINATION_POLICIES_COLUMNS = [
|
|
4194
4206
|
{
|
|
@@ -4575,6 +4587,18 @@ var LocationManifestLock = class {
|
|
|
4575
4587
|
};
|
|
4576
4588
|
//#endregion
|
|
4577
4589
|
//#region src/builtins/backup-orchestrator/schedule-store.ts
|
|
4590
|
+
/**
|
|
4591
|
+
* @durable class=config owner=backup-orchestrator
|
|
4592
|
+
* write="an operator creating or editing a schedule (`upsert`, implemented as
|
|
4593
|
+
* delete + insert: cron, enabled, the fan-out `location_ids`, `retention_count`,
|
|
4594
|
+
* optional `data_sources`), plus a `last_run_at` stamp the orchestrator writes on
|
|
4595
|
+
* every due tick BEFORE the archive runs, so an upload outliving the tick cannot
|
|
4596
|
+
* fire the same schedule twice"
|
|
4597
|
+
* retention="only the operator's `delete(id)` — no sweep, no expiry, and `retention_count`
|
|
4598
|
+
* bounds the ARCHIVES at the destination, never these rows. Losing the table stops
|
|
4599
|
+
* every scheduled backup silently: no cron remains to fire, and the fan-out sets and
|
|
4600
|
+
* retention counts are gone with it."
|
|
4601
|
+
*/
|
|
4578
4602
|
var BACKUP_SCHEDULES = "backup_schedules";
|
|
4579
4603
|
var BACKUP_SCHEDULES_COLUMNS = [
|
|
4580
4604
|
{
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/console-logging/console-destination.ts
|
|
9
9
|
var LEVEL_RANK = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-
|
|
1
|
+
import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/console-logging/console-destination.ts
|
|
4
4
|
var LEVEL_RANK = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeclaredDevicePorts } from '@camstack/types';
|
|
1
|
+
import { DeclaredDevicePorts, IScopedLogger } from '@camstack/types';
|
|
2
2
|
/** Operator-visible name of the shared integration. Seeded once, at create. */
|
|
3
3
|
export declare const BLOCKS_INTEGRATION_NAME = "Blocks";
|
|
4
4
|
/**
|
|
@@ -22,3 +22,36 @@ export type BlocksIntegrationPorts = Omit<DeclaredDevicePorts, 'addonId'>;
|
|
|
22
22
|
* convenience; the spec test pins both.
|
|
23
23
|
*/
|
|
24
24
|
export declare function reconcileBlocksIntegration(ports: BlocksIntegrationPorts): Promise<string | null>;
|
|
25
|
+
/** What {@link armBlocksIntegration} needs, and the seam its spec drives. */
|
|
26
|
+
export interface ArmBlocksIntegrationOptions {
|
|
27
|
+
readonly logger: IScopedLogger;
|
|
28
|
+
readonly reconcile: () => Promise<string | null>;
|
|
29
|
+
readonly onLanded: (integrationId: string | null) => void;
|
|
30
|
+
readonly retryDelayMs?: number;
|
|
31
|
+
readonly maxAttempts?: number;
|
|
32
|
+
}
|
|
33
|
+
/** A reconcile running in the background, and a handle to await in tests. */
|
|
34
|
+
export interface ArmedBlocksIntegration {
|
|
35
|
+
readonly settled: Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Arm the shared integration WITHOUT putting it on the boot path (D167).
|
|
39
|
+
*
|
|
40
|
+
* `integrations` is a hub-core namespace served by the `$core-caps` Moleculer
|
|
41
|
+
* service, and that service is registered only after `app.init()` returns —
|
|
42
|
+
* which is where the entire addon boot runs. During boot the read is therefore
|
|
43
|
+
* not slow, it is unanswerable: it burns the full 30 s discovery deadline and
|
|
44
|
+
* fast-fails, with no boot-window retry (core caps are excluded from it).
|
|
45
|
+
*
|
|
46
|
+
* Awaited inside `onInitialize()`, that 30 s sat on the hub's SERIAL in-process
|
|
47
|
+
* builtin loop and delayed `device-manager` — which every provider runner waits
|
|
48
|
+
* on before it may publish a single capability. Measured 2026-08-15: builtins
|
|
49
|
+
* stalled t0+10 s → t0+40 s, and the first camera's first keyframe landed at
|
|
50
|
+
* t0+75 s.
|
|
51
|
+
*
|
|
52
|
+
* So: arm it, let boot finish, and let the retry land it a few seconds later. A
|
|
53
|
+
* block that declares a device before it lands finds `null` and gets the
|
|
54
|
+
* integration on the next converge tick — which was already the documented
|
|
55
|
+
* behaviour when the API was unavailable.
|
|
56
|
+
*/
|
|
57
|
+
export declare function armBlocksIntegration(options: ArmBlocksIntegrationOptions): ArmedBlocksIntegration;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { CoreBlock, CoreBlockInput, IScopedLogger, SettingsStoreClient } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* @durable class=config owner=core-blocks
|
|
4
|
+
* write="`create` and `update` persist the operator's block after it compiles;
|
|
5
|
+
* `setStatus` rewrites what the runner reported (status, `lastChangedAt`,
|
|
6
|
+
* `lastError`) — so a running block is written on every state change"
|
|
7
|
+
* retention="`delete` only, when the operator removes a block. Nothing ages out,
|
|
8
|
+
* and a row whose JSON stops validating is left on disk rather than repaired.
|
|
9
|
+
* The real loss path is a `declareCollection` REBUILD — a legacy (id, data)
|
|
10
|
+
* shape, or a new PK/UNIQUE/NOT-NULL-without-default column — which drops the
|
|
11
|
+
* table and takes the operator's source code with it."
|
|
12
|
+
*/
|
|
2
13
|
export declare const CORE_BLOCKS_COLLECTION = "core_blocks";
|
|
3
14
|
export declare const CORE_BLOCKS_COLUMNS: readonly [{
|
|
4
15
|
readonly name: "id";
|
|
@@ -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-BH2tZ9ZN.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -495,6 +495,17 @@ async function compileBlock(transpiler, code) {
|
|
|
495
495
|
* is a fork failure the operator meets minutes later inside a log — so the
|
|
496
496
|
* compile happens where they are still looking at the editor.
|
|
497
497
|
*/
|
|
498
|
+
/**
|
|
499
|
+
* @durable class=config owner=core-blocks
|
|
500
|
+
* write="`create` and `update` persist the operator's block after it compiles;
|
|
501
|
+
* `setStatus` rewrites what the runner reported (status, `lastChangedAt`,
|
|
502
|
+
* `lastError`) — so a running block is written on every state change"
|
|
503
|
+
* retention="`delete` only, when the operator removes a block. Nothing ages out,
|
|
504
|
+
* and a row whose JSON stops validating is left on disk rather than repaired.
|
|
505
|
+
* The real loss path is a `declareCollection` REBUILD — a legacy (id, data)
|
|
506
|
+
* shape, or a new PK/UNIQUE/NOT-NULL-without-default column — which drops the
|
|
507
|
+
* table and takes the operator's source code with it."
|
|
508
|
+
*/
|
|
498
509
|
var CORE_BLOCKS_COLLECTION = "core_blocks";
|
|
499
510
|
var CORE_BLOCKS_COLUMNS = [
|
|
500
511
|
{
|
|
@@ -721,6 +732,52 @@ async function reconcileBlocksIntegration(ports) {
|
|
|
721
732
|
devices: []
|
|
722
733
|
})).integrationId;
|
|
723
734
|
}
|
|
735
|
+
/** Retry cadence for {@link armBlocksIntegration}. The gap it waits out is the
|
|
736
|
+
* rest of hub boot — `$core-caps` is registered once `app.init()` returns — so
|
|
737
|
+
* seconds, and a handful of them, is the right shape. */
|
|
738
|
+
var ARM_RETRY_DELAY_MS = 5e3;
|
|
739
|
+
/** Bounded, because an integration that will never reconcile must say so once
|
|
740
|
+
* rather than log forever. Roughly two minutes at the default cadence. */
|
|
741
|
+
var ARM_MAX_ATTEMPTS = 24;
|
|
742
|
+
/**
|
|
743
|
+
* Arm the shared integration WITHOUT putting it on the boot path (D167).
|
|
744
|
+
*
|
|
745
|
+
* `integrations` is a hub-core namespace served by the `$core-caps` Moleculer
|
|
746
|
+
* service, and that service is registered only after `app.init()` returns —
|
|
747
|
+
* which is where the entire addon boot runs. During boot the read is therefore
|
|
748
|
+
* not slow, it is unanswerable: it burns the full 30 s discovery deadline and
|
|
749
|
+
* fast-fails, with no boot-window retry (core caps are excluded from it).
|
|
750
|
+
*
|
|
751
|
+
* Awaited inside `onInitialize()`, that 30 s sat on the hub's SERIAL in-process
|
|
752
|
+
* builtin loop and delayed `device-manager` — which every provider runner waits
|
|
753
|
+
* on before it may publish a single capability. Measured 2026-08-15: builtins
|
|
754
|
+
* stalled t0+10 s → t0+40 s, and the first camera's first keyframe landed at
|
|
755
|
+
* t0+75 s.
|
|
756
|
+
*
|
|
757
|
+
* So: arm it, let boot finish, and let the retry land it a few seconds later. A
|
|
758
|
+
* block that declares a device before it lands finds `null` and gets the
|
|
759
|
+
* integration on the next converge tick — which was already the documented
|
|
760
|
+
* behaviour when the API was unavailable.
|
|
761
|
+
*/
|
|
762
|
+
function armBlocksIntegration(options) {
|
|
763
|
+
const retryDelayMs = options.retryDelayMs ?? ARM_RETRY_DELAY_MS;
|
|
764
|
+
const maxAttempts = options.maxAttempts ?? ARM_MAX_ATTEMPTS;
|
|
765
|
+
return { settled: (async () => {
|
|
766
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
|
|
767
|
+
options.onLanded(await options.reconcile());
|
|
768
|
+
return;
|
|
769
|
+
} catch (err) {
|
|
770
|
+
if (attempt === maxAttempts) {
|
|
771
|
+
options.logger.warn("core-blocks: the shared integration never reconciled — a block that declares a device has nowhere to hang it", { meta: {
|
|
772
|
+
attempts: attempt,
|
|
773
|
+
error: require_dist.errMsg(err)
|
|
774
|
+
} });
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
778
|
+
}
|
|
779
|
+
})() };
|
|
780
|
+
}
|
|
724
781
|
//#endregion
|
|
725
782
|
//#region src/builtins/core-blocks/core-blocks.addon.ts
|
|
726
783
|
/**
|
|
@@ -777,7 +834,13 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
777
834
|
});
|
|
778
835
|
await this.store.load();
|
|
779
836
|
this.transpiler = await loadTranspiler(this.ctx.logger);
|
|
780
|
-
|
|
837
|
+
armBlocksIntegration({
|
|
838
|
+
logger: this.ctx.logger,
|
|
839
|
+
reconcile: () => this.declareBlocksIntegration(),
|
|
840
|
+
onLanded: (integrationId) => {
|
|
841
|
+
this.blocksIntegrationId = integrationId;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
781
844
|
this.supervisor = this.buildSupervisor();
|
|
782
845
|
this.supervisor?.start(CONVERGE_INTERVAL_MS);
|
|
783
846
|
this.ctx.logger.info("core-blocks ready", { meta: {
|
|
@@ -857,26 +920,21 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
857
920
|
this.ctx.logger.warn("core-blocks: no integrations API — a block that declares a device will have nowhere to hang it");
|
|
858
921
|
return null;
|
|
859
922
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
});
|
|
876
|
-
} catch (err) {
|
|
877
|
-
this.ctx.logger.warn("core-blocks: the shared integration could not be reconciled", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
878
|
-
return null;
|
|
879
|
-
}
|
|
923
|
+
return reconcileBlocksIntegration({
|
|
924
|
+
logger: this.ctx.logger.child("integration"),
|
|
925
|
+
devices: this.ctx.kernel.devices,
|
|
926
|
+
localNodeId: this.ctx.kernel.localNodeId,
|
|
927
|
+
getIntegration: async (addonId) => api.integrations.getByAddonId.query({ addonId }),
|
|
928
|
+
createIntegration: async (input) => api.integrations.create.mutate(input),
|
|
929
|
+
updateIntegration: async ({ id, info }) => {
|
|
930
|
+
await api.integrations.update.mutate({
|
|
931
|
+
id,
|
|
932
|
+
info,
|
|
933
|
+
skipRestart: true
|
|
934
|
+
});
|
|
935
|
+
},
|
|
936
|
+
listOwnDevices: async () => api.deviceManager.listAll.query({ addonId: require_dist.CORE_BLOCKS_ADDON_ID })
|
|
937
|
+
});
|
|
880
938
|
}
|
|
881
939
|
/**
|
|
882
940
|
* Reconcile now, after a write.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as coreBlockIdFromAddonId, E as coreBlockAddonId, O as coreBlocksCapability, _t as BaseAddon, c as CoreBlockSchema, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX } from "../../dist-
|
|
1
|
+
import { D as coreBlockIdFromAddonId, E as coreBlockAddonId, O as coreBlocksCapability, _t as BaseAddon, c as CoreBlockSchema, gt as errMsg, l as DeclaredDevices, o as CORE_BLOCKS_ADDON_ID, s as CORE_BLOCK_ADDON_PREFIX } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -491,6 +491,17 @@ async function compileBlock(transpiler, code) {
|
|
|
491
491
|
* is a fork failure the operator meets minutes later inside a log — so the
|
|
492
492
|
* compile happens where they are still looking at the editor.
|
|
493
493
|
*/
|
|
494
|
+
/**
|
|
495
|
+
* @durable class=config owner=core-blocks
|
|
496
|
+
* write="`create` and `update` persist the operator's block after it compiles;
|
|
497
|
+
* `setStatus` rewrites what the runner reported (status, `lastChangedAt`,
|
|
498
|
+
* `lastError`) — so a running block is written on every state change"
|
|
499
|
+
* retention="`delete` only, when the operator removes a block. Nothing ages out,
|
|
500
|
+
* and a row whose JSON stops validating is left on disk rather than repaired.
|
|
501
|
+
* The real loss path is a `declareCollection` REBUILD — a legacy (id, data)
|
|
502
|
+
* shape, or a new PK/UNIQUE/NOT-NULL-without-default column — which drops the
|
|
503
|
+
* table and takes the operator's source code with it."
|
|
504
|
+
*/
|
|
494
505
|
var CORE_BLOCKS_COLLECTION = "core_blocks";
|
|
495
506
|
var CORE_BLOCKS_COLUMNS = [
|
|
496
507
|
{
|
|
@@ -717,6 +728,52 @@ async function reconcileBlocksIntegration(ports) {
|
|
|
717
728
|
devices: []
|
|
718
729
|
})).integrationId;
|
|
719
730
|
}
|
|
731
|
+
/** Retry cadence for {@link armBlocksIntegration}. The gap it waits out is the
|
|
732
|
+
* rest of hub boot — `$core-caps` is registered once `app.init()` returns — so
|
|
733
|
+
* seconds, and a handful of them, is the right shape. */
|
|
734
|
+
var ARM_RETRY_DELAY_MS = 5e3;
|
|
735
|
+
/** Bounded, because an integration that will never reconcile must say so once
|
|
736
|
+
* rather than log forever. Roughly two minutes at the default cadence. */
|
|
737
|
+
var ARM_MAX_ATTEMPTS = 24;
|
|
738
|
+
/**
|
|
739
|
+
* Arm the shared integration WITHOUT putting it on the boot path (D167).
|
|
740
|
+
*
|
|
741
|
+
* `integrations` is a hub-core namespace served by the `$core-caps` Moleculer
|
|
742
|
+
* service, and that service is registered only after `app.init()` returns —
|
|
743
|
+
* which is where the entire addon boot runs. During boot the read is therefore
|
|
744
|
+
* not slow, it is unanswerable: it burns the full 30 s discovery deadline and
|
|
745
|
+
* fast-fails, with no boot-window retry (core caps are excluded from it).
|
|
746
|
+
*
|
|
747
|
+
* Awaited inside `onInitialize()`, that 30 s sat on the hub's SERIAL in-process
|
|
748
|
+
* builtin loop and delayed `device-manager` — which every provider runner waits
|
|
749
|
+
* on before it may publish a single capability. Measured 2026-08-15: builtins
|
|
750
|
+
* stalled t0+10 s → t0+40 s, and the first camera's first keyframe landed at
|
|
751
|
+
* t0+75 s.
|
|
752
|
+
*
|
|
753
|
+
* So: arm it, let boot finish, and let the retry land it a few seconds later. A
|
|
754
|
+
* block that declares a device before it lands finds `null` and gets the
|
|
755
|
+
* integration on the next converge tick — which was already the documented
|
|
756
|
+
* behaviour when the API was unavailable.
|
|
757
|
+
*/
|
|
758
|
+
function armBlocksIntegration(options) {
|
|
759
|
+
const retryDelayMs = options.retryDelayMs ?? ARM_RETRY_DELAY_MS;
|
|
760
|
+
const maxAttempts = options.maxAttempts ?? ARM_MAX_ATTEMPTS;
|
|
761
|
+
return { settled: (async () => {
|
|
762
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
|
|
763
|
+
options.onLanded(await options.reconcile());
|
|
764
|
+
return;
|
|
765
|
+
} catch (err) {
|
|
766
|
+
if (attempt === maxAttempts) {
|
|
767
|
+
options.logger.warn("core-blocks: the shared integration never reconciled — a block that declares a device has nowhere to hang it", { meta: {
|
|
768
|
+
attempts: attempt,
|
|
769
|
+
error: errMsg(err)
|
|
770
|
+
} });
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
774
|
+
}
|
|
775
|
+
})() };
|
|
776
|
+
}
|
|
720
777
|
//#endregion
|
|
721
778
|
//#region src/builtins/core-blocks/core-blocks.addon.ts
|
|
722
779
|
/**
|
|
@@ -773,7 +830,13 @@ var CoreBlocksAddon = class extends BaseAddon {
|
|
|
773
830
|
});
|
|
774
831
|
await this.store.load();
|
|
775
832
|
this.transpiler = await loadTranspiler(this.ctx.logger);
|
|
776
|
-
|
|
833
|
+
armBlocksIntegration({
|
|
834
|
+
logger: this.ctx.logger,
|
|
835
|
+
reconcile: () => this.declareBlocksIntegration(),
|
|
836
|
+
onLanded: (integrationId) => {
|
|
837
|
+
this.blocksIntegrationId = integrationId;
|
|
838
|
+
}
|
|
839
|
+
});
|
|
777
840
|
this.supervisor = this.buildSupervisor();
|
|
778
841
|
this.supervisor?.start(CONVERGE_INTERVAL_MS);
|
|
779
842
|
this.ctx.logger.info("core-blocks ready", { meta: {
|
|
@@ -853,26 +916,21 @@ var CoreBlocksAddon = class extends BaseAddon {
|
|
|
853
916
|
this.ctx.logger.warn("core-blocks: no integrations API — a block that declares a device will have nowhere to hang it");
|
|
854
917
|
return null;
|
|
855
918
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
});
|
|
872
|
-
} catch (err) {
|
|
873
|
-
this.ctx.logger.warn("core-blocks: the shared integration could not be reconciled", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
874
|
-
return null;
|
|
875
|
-
}
|
|
919
|
+
return reconcileBlocksIntegration({
|
|
920
|
+
logger: this.ctx.logger.child("integration"),
|
|
921
|
+
devices: this.ctx.kernel.devices,
|
|
922
|
+
localNodeId: this.ctx.kernel.localNodeId,
|
|
923
|
+
getIntegration: async (addonId) => api.integrations.getByAddonId.query({ addonId }),
|
|
924
|
+
createIntegration: async (input) => api.integrations.create.mutate(input),
|
|
925
|
+
updateIntegration: async ({ id, info }) => {
|
|
926
|
+
await api.integrations.update.mutate({
|
|
927
|
+
id,
|
|
928
|
+
info,
|
|
929
|
+
skipRestart: true
|
|
930
|
+
});
|
|
931
|
+
},
|
|
932
|
+
listOwnDevices: async () => api.deviceManager.listAll.query({ addonId: CORE_BLOCKS_ADDON_ID })
|
|
933
|
+
});
|
|
876
934
|
}
|
|
877
935
|
/**
|
|
878
936
|
* Reconcile now, after a write.
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let _camstack_types_node = require("@camstack/types/node");
|
|
9
9
|
//#region src/builtins/device-manager/adoption-job-engine.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as DeviceType, Et as WELL_KNOWN_TAB_MAP, Ft as isDeviceConfigCap, Ht as sleep, I as enumerateItemArrayFields, L as enumerateSchemaFields, M as deviceStateCapability, N as deviceStatusCapability, Q as normalizeUnit, St as DeviceRole, T as buildStreamParamsConfigSchema, Ut as EventCategory, _t as BaseAddon, a as CAP_NAMES_WITH_STATUS, et as parseStreamParamsFormPatch, gt as errMsg, j as deviceManagerCapability, p as STREAM_PROFILE_META, rt as runtimeStatePolicyFor, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, xt as DeviceFeature } from "../../dist-
|
|
1
|
+
import { Ct as DeviceType, Et as WELL_KNOWN_TAB_MAP, Ft as isDeviceConfigCap, Ht as sleep, I as enumerateItemArrayFields, L as enumerateSchemaFields, M as deviceStateCapability, N as deviceStatusCapability, Q as normalizeUnit, St as DeviceRole, T as buildStreamParamsConfigSchema, Ut as EventCategory, _t as BaseAddon, a as CAP_NAMES_WITH_STATUS, et as parseStreamParamsFormPatch, gt as errMsg, j as deviceManagerCapability, p as STREAM_PROFILE_META, rt as runtimeStatePolicyFor, t as ALL_CAPABILITY_DEFINITIONS, u as DeviceStatusSchema, xt as DeviceFeature } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { canonicalDeviceFingerprint } from "@camstack/types/node";
|
|
4
4
|
//#region src/builtins/device-manager/adoption-job-engine.ts
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
//#region src/builtins/doorbell/trigger-engine.ts
|
|
8
8
|
/**
|
|
9
9
|
* Pure trigger logic for the virtual-doorbell builtin — edge detection over
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as createEvent, Ct as DeviceType, P as doorbellCapability, U as isSameAddonId, Ut as EventCategory, _t as BaseAddon, gt as errMsg, w as bareAddonId } from "../../dist-
|
|
1
|
+
import { At as createEvent, Ct as DeviceType, P as doorbellCapability, U as isSameAddonId, Ut as EventCategory, _t as BaseAddon, gt as errMsg, w as bareAddonId } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
//#region src/builtins/doorbell/trigger-engine.ts
|
|
3
3
|
/**
|
|
4
4
|
* Pure trigger logic for the virtual-doorbell builtin — edge detection over
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
//#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
|
|
9
9
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-
|
|
1
|
+
import { J as logDestinationCapability, _t as BaseAddon } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
//#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
|
|
4
4
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-BH2tZ9ZN.js");
|
|
4
4
|
//#region src/builtins/liveness-monitor/liveness-checks.ts
|
|
5
5
|
var NO_DEVICES = "liveness:no-devices";
|
|
6
6
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg } from "../../dist-
|
|
1
|
+
import { At as createEvent, Ut as EventCategory, _t as BaseAddon, gt as errMsg } from "../../dist-DXDvrBi0.mjs";
|
|
2
2
|
//#region src/builtins/liveness-monitor/liveness-checks.ts
|
|
3
3
|
var NO_DEVICES = "liveness:no-devices";
|
|
4
4
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { SettingsStoreClient } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* @durable class=config owner=local-auth
|
|
4
|
+
* write="an operator creates a user, or `ensureAdminExists` seeds/re-syncs the
|
|
5
|
+
* configured admin at boot; updated on scope, isAdmin and password edits"
|
|
6
|
+
* retention="none — a row goes only when an operator deletes the user. A
|
|
7
|
+
* `declareCollection` that adds a PK/UNIQUE/NOT-NULL-without-default column
|
|
8
|
+
* REBUILDS the table: every account is wiped and only the configured admin
|
|
9
|
+
* comes back on the next boot."
|
|
10
|
+
*/
|
|
2
11
|
export declare const USERS_COLLECTION = "users";
|
|
12
|
+
/**
|
|
13
|
+
* @durable class=config owner=local-auth
|
|
14
|
+
* write="an operator mints an API key; `validateToken` rewrites `lastUsedAt` on
|
|
15
|
+
* every request the key authorises"
|
|
16
|
+
* retention="none — an explicit `revoke` is the only delete. API keys have no
|
|
17
|
+
* expiry column and no sweep, so a key lives until someone removes it (or the
|
|
18
|
+
* destructive `declareCollection` rebuild takes the table)."
|
|
19
|
+
*/
|
|
3
20
|
export declare const API_KEYS_COLLECTION = "api_keys";
|
|
21
|
+
/**
|
|
22
|
+
* @durable class=config owner=local-auth
|
|
23
|
+
* write="an operator or the CLI mints a scoped token; `validate` fires
|
|
24
|
+
* `updateLastUsed` on every accepted call"
|
|
25
|
+
* retention="`revoke` deletes one. The daily sweep `reapExpired` drops rows past
|
|
26
|
+
* `expiresAt` — a NULL expiry is a deliberate never-expires token and BETWEEN
|
|
27
|
+
* never matches it. `cleanupOrphans` drops tokens owned by the legacy 'system'
|
|
28
|
+
* id or by a user that no longer exists."
|
|
29
|
+
*/
|
|
4
30
|
export declare const SCOPED_TOKENS_COLLECTION = "scoped_tokens";
|
|
31
|
+
/**
|
|
32
|
+
* @durable class=ledger owner=local-auth
|
|
33
|
+
* write="one row per redeemed OAuth code — every completed account link through
|
|
34
|
+
* `oauthExchangeCode`; `touch` rewrites `lastUsedAt` on each refresh"
|
|
35
|
+
* retention="ONLY revoked rows are pruned: the daily sweep deletes sessions
|
|
36
|
+
* revoked more than OAUTH_REVOKED_RETENTION_MS (30 d) ago. An ACTIVE session
|
|
37
|
+
* has `revokedAt` NULL, never expires and is never swept — the table grows one
|
|
38
|
+
* row per login until an operator revokes the link."
|
|
39
|
+
*/
|
|
5
40
|
export declare const OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
|
|
6
41
|
/**
|
|
7
42
|
* TOTP enrollment table — split off from `users` to avoid the
|
|
@@ -15,6 +50,13 @@ export declare const OAUTH_SESSIONS_COLLECTION = "oauth_sessions";
|
|
|
15
50
|
*
|
|
16
51
|
* "Enabled" means `confirmedAt != null`. A half-enrolled row (`confirmedAt
|
|
17
52
|
* = null`) is INACTIVE — `verifyTotp` returns false until confirmation.
|
|
53
|
+
*
|
|
54
|
+
* @durable class=config owner=local-auth
|
|
55
|
+
* write="`setup` inserts a fresh secret for the user (deleting any pending row
|
|
56
|
+
* first); `confirm` flips `confirmedAt` once a valid code proves possession"
|
|
57
|
+
* retention="`disable` deletes the row, and `setup` deletes before re-inserting.
|
|
58
|
+
* Nothing else prunes — deleting a USER does not cascade here, so their
|
|
59
|
+
* enrollment row outlives the account."
|
|
18
60
|
*/
|
|
19
61
|
export declare const USER_TOTP_COLLECTION = "user_totp";
|
|
20
62
|
/**
|