@camstack/system 1.2.357 → 1.2.359

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 +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/auth/user-manager.d.ts +43 -2
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/alerts/alerts.addon.js +1 -1
  9. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  10. package/dist/builtins/autotrack/index.js +2 -2
  11. package/dist/builtins/autotrack/index.mjs +2 -2
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  13. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  14. package/dist/builtins/calendars/calendars.addon.js +1 -1
  15. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  16. package/dist/builtins/camera-grid/index.js +1 -1
  17. package/dist/builtins/camera-grid/index.mjs +1 -1
  18. package/dist/builtins/composer/composer.addon.js +8 -8
  19. package/dist/builtins/composer/composer.addon.mjs +8 -8
  20. package/dist/builtins/console-logging/index.js +1 -1
  21. package/dist/builtins/console-logging/index.mjs +1 -1
  22. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  23. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  24. package/dist/builtins/device-manager/device-manager.addon.js +9 -9
  25. package/dist/builtins/device-manager/device-manager.addon.mjs +9 -9
  26. package/dist/builtins/hub-forwarder/index.js +1 -1
  27. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  28. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  29. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  30. package/dist/builtins/local-auth/admin-account-boot.d.ts +27 -0
  31. package/dist/builtins/local-auth/auth-schema.d.ts +3 -2
  32. package/dist/builtins/local-auth/local-auth.addon.js +281 -8
  33. package/dist/builtins/local-auth/local-auth.addon.mjs +291 -22
  34. package/dist/builtins/local-network/address-book.d.ts +69 -0
  35. package/dist/builtins/local-network/local-network.addon.d.ts +44 -32
  36. package/dist/builtins/local-network/local-network.addon.js +368 -55
  37. package/dist/builtins/local-network/local-network.addon.mjs +369 -54
  38. package/dist/builtins/loki-logging/index.js +1 -1
  39. package/dist/builtins/loki-logging/index.mjs +1 -1
  40. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  41. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  42. package/dist/builtins/platform-probe/index.js +1 -1
  43. package/dist/builtins/platform-probe/index.mjs +1 -1
  44. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  45. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  46. package/dist/builtins/snapshot/index.js +1 -1
  47. package/dist/builtins/snapshot/index.mjs +1 -1
  48. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  49. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  50. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  51. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  52. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  53. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/system-config/system-config.addon.js +1 -1
  55. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  56. package/dist/builtins/winston-logging/index.js +1 -1
  57. package/dist/builtins/winston-logging/index.mjs +1 -1
  58. package/dist/{child-cap-dispatch-BcRHQBKW.mjs → child-cap-dispatch-Dm1TRDCr.mjs} +2 -2
  59. package/dist/{child-cap-dispatch-wbIQJctP.js → child-cap-dispatch-t61ohDpb.js} +2 -2
  60. package/dist/{composition-sources-CeO0K2cl.js → composition-sources-CCU_KizO.js} +1 -1
  61. package/dist/{composition-sources-BBfqepyT.mjs → composition-sources-CHlfWHl6.mjs} +1 -1
  62. package/dist/{dist-CFVOy8VT.js → dist-W_X44h-s.js} +669 -121
  63. package/dist/{dist-B7WRgEZY.mjs → dist-pTfD_M-U.mjs} +628 -122
  64. package/dist/index.js +6 -141
  65. package/dist/index.mjs +4 -139
  66. package/dist/kernel/config-manager.d.ts +1 -1
  67. package/dist/kernel/config-schema.d.ts +6 -1
  68. package/dist/{retired-settings-keys-DKRjfz0U.mjs → retired-settings-keys-CK_ifret.mjs} +1 -1
  69. package/dist/{retired-settings-keys-CRlTzxaS.js → retired-settings-keys-jglEzgWR.js} +1 -1
  70. package/package.json +3 -3
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_child_cap_dispatch = require("./child-cap-dispatch-wbIQJctP.js");
2
+ const require_child_cap_dispatch = require("./child-cap-dispatch-t61ohDpb.js");
3
3
  const require_custom_action_registry = require("./custom-action-registry-acBY3mHA.js");
4
4
  let node_path = require("node:path");
5
5
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { $t as RUNNER_RSS_BUDGET_ENV, Ft as resolveAddonClass, H as createUdsLoggerWithControl, Pt as installManifestNativeDeps, U as LocalChildClient, _t as getWorkerNativeCapSnapshot, f as installManifestSystemDeps, fn as startRunnerHeapWatch, g as createUdsAddonContext, gt as getWorkerNativeCapProvider, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, u as startRunnerParentDeathWatchdog, wn as emitHeapDiagnosticReport, xt as validateProviderRegistrations, yt as setWorkerNativeCapsChangeListener } from "./child-cap-dispatch-BcRHQBKW.mjs";
1
+ import { $t as RUNNER_RSS_BUDGET_ENV, Ft as resolveAddonClass, H as createUdsLoggerWithControl, Pt as installManifestNativeDeps, U as LocalChildClient, _t as getWorkerNativeCapSnapshot, f as installManifestSystemDeps, fn as startRunnerHeapWatch, g as createUdsAddonContext, gt as getWorkerNativeCapProvider, i as killOwnRunnerGroupAfterParentLoss, n as createChildCapDispatch, p as installManifestPythonDeps, u as startRunnerParentDeathWatchdog, wn as emitHeapDiagnosticReport, xt as validateProviderRegistrations, yt as setWorkerNativeCapsChangeListener } from "./child-cap-dispatch-Dm1TRDCr.mjs";
2
2
  import { t as CustomActionRegistry } from "./custom-action-registry-B4Cf4O_X.mjs";
3
3
  import { register } from "node:module";
4
4
  import * as path$1 from "node:path";
@@ -1,5 +1,5 @@
1
+ import { SettingsStoreClient, TokenScope, UserRecord } from '@camstack/types';
1
2
  import { AuthManager } from './auth-manager.js';
2
- import { UserRecord, TokenScope, SettingsStoreClient } from '@camstack/types';
3
3
  export type { UserRecord };
4
4
  interface CreateUserInput {
5
5
  username: string;
@@ -10,6 +10,26 @@ interface CreateUserInput {
10
10
  scopes?: TokenScope[];
11
11
  }
12
12
  type UpdatableUserFields = Partial<Pick<UserRecord, 'isAdmin' | 'allowedProviders' | 'allowedDevices' | 'scopes'>>;
13
+ export interface EnsureAdminOptions {
14
+ /** The operator's explicit, one-shot recovery request. Never a default. */
15
+ readonly resetPassword?: boolean;
16
+ }
17
+ /** What `ensureAdminExists` did — every branch is named so the caller can log it. */
18
+ export type AdminSeedOutcome = {
19
+ readonly kind: 'not-configured';
20
+ } | {
21
+ readonly kind: 'seeded';
22
+ readonly username: string;
23
+ } | {
24
+ readonly kind: 'exists';
25
+ readonly username: string;
26
+ } | {
27
+ readonly kind: 'other-admin-exists';
28
+ readonly username: string;
29
+ } | {
30
+ readonly kind: 'reset';
31
+ readonly username: string;
32
+ };
13
33
  export interface UserStorageAccess {
14
34
  getStore(): SettingsStoreClient;
15
35
  }
@@ -31,5 +51,26 @@ export declare class UserManager {
31
51
  update(id: string, data: UpdatableUserFields): Promise<void>;
32
52
  delete(id: string): Promise<void>;
33
53
  resetPassword(id: string, newPassword: string): Promise<void>;
34
- ensureAdminExists(): Promise<void>;
54
+ /**
55
+ * Seed the configured admin (`auth.adminUsername` / `auth.adminPassword`,
56
+ * i.e. `CAMSTACK_ADMIN_USER` / `CAMSTACK_ADMIN_PASS`) — on FIRST boot only.
57
+ *
58
+ * The configured password is a seed, never an authority. Once any admin
59
+ * exists, this never writes a password: the operator's own change in the
60
+ * admin UI is the truth from then on. This method used to compare the stored
61
+ * hash with the configured password on every boot and rewrite it when they
62
+ * differed, so a password changed in the UI went back to the configured one
63
+ * (`changeme` on a Mac hub and on any container without `CAMSTACK_ADMIN_PASS`)
64
+ * at the next restart.
65
+ *
66
+ * `resetPassword: true` is the one explicit exception — the operator's
67
+ * one-shot recovery request (see `admin-password-reset.ts`): the configured
68
+ * admin's password is set back to the configured one.
69
+ */
70
+ ensureAdminExists(options?: EnsureAdminOptions): Promise<AdminSeedOutcome>;
71
+ /**
72
+ * Does `username` still sign in with `password`? A hash comparison — the
73
+ * password is never logged or stored. `false` when the user does not exist.
74
+ */
75
+ hasPassword(username: string, password: string): Promise<boolean>;
35
76
  }
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.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 { Cr as EventCategory, Qn as BaseAddon, U as addonPagesCapability, Zn as errMsg } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, U as addonPagesCapability, ar as BaseAddon, ir as errMsg } from "../../dist-pTfD_M-U.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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.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 { Cr as EventCategory, G as addonWidgetsCapability, Qn as BaseAddon, Zn as errMsg } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, G as addonWidgetsCapability, ar as BaseAddon, ir as errMsg } from "../../dist-pTfD_M-U.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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
7
  //#region src/builtins/alerts/device-label.ts
8
8
  /**
9
9
  * Operator-facing device label for alert messages.
@@ -1,4 +1,4 @@
1
- import { Cr as EventCategory, K as alertsCapability, Qn as BaseAddon, Zn as errMsg, cr as createEvent, n as AlertSchema } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, K as alertsCapability, ar as BaseAddon, hr as createEvent, ir as errMsg, n as AlertSchema } from "../../dist-pTfD_M-U.mjs";
2
2
  //#region src/builtins/alerts/device-label.ts
3
3
  /**
4
4
  * Operator-facing device label for alert messages.
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
7
  //#region src/builtins/autotrack/autotrack-config.ts
8
8
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
9
9
  deadZoneFraction: .5,
@@ -113,7 +113,7 @@ function parseZoom(raw) {
113
113
  function zoomRefusalFor(record) {
114
114
  const target = record.zoom.targetSubjectFraction;
115
115
  if (target === null) return null;
116
- return `autotrack zoom is configured (target subject fraction ${String(target)}) but NOT IMPLEMENTED: the loop drives pan and tilt only. Subject-size control needs a third axis with its own dead band, a rule that it may act only while pan/tilt are settled, and the two D520 measurements first — a stale error costs more the further the optics are zoomed in.`;
116
+ return `autotrack zoom is configured (target subject fraction ${String(target)}) but NOT IMPLEMENTED: the loop drives pan and tilt only. Subject-size control needs a third axis with its own dead band, a rule that it may act only while pan/tilt are settled, and two calibration measurements first — a stale error costs more the further the optics are zoomed in.`;
117
117
  }
118
118
  function parseCameraRecords(raw) {
119
119
  if (!isRecordObject(raw)) return {};
@@ -1,4 +1,4 @@
1
- import { Cr as EventCategory, Qn as BaseAddon, S as FIRST_LEVEL_MACRO_CLASSES, Y as bareAddonId, Zn as errMsg, ln as ptzAutotrackCapability, mr as isEvent } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, S as FIRST_LEVEL_MACRO_CLASSES, Y as bareAddonId, ar as BaseAddon, fn as ptzAutotrackCapability, ir as errMsg, xr as isEvent } from "../../dist-pTfD_M-U.mjs";
2
2
  //#region src/builtins/autotrack/autotrack-config.ts
3
3
  var DEFAULT_AUTOTRACK_LOOP_CONFIG = {
4
4
  deadZoneFraction: .5,
@@ -108,7 +108,7 @@ function parseZoom(raw) {
108
108
  function zoomRefusalFor(record) {
109
109
  const target = record.zoom.targetSubjectFraction;
110
110
  if (target === null) return null;
111
- return `autotrack zoom is configured (target subject fraction ${String(target)}) but NOT IMPLEMENTED: the loop drives pan and tilt only. Subject-size control needs a third axis with its own dead band, a rule that it may act only while pan/tilt are settled, and the two D520 measurements first — a stale error costs more the further the optics are zoomed in.`;
111
+ return `autotrack zoom is configured (target subject fraction ${String(target)}) but NOT IMPLEMENTED: the loop drives pan and tilt only. Subject-size control needs a third axis with its own dead band, a rule that it may act only while pan/tilt are settled, and two calibration measurements first — a stale error costs more the further the optics are zoomed in.`;
112
112
  }
113
113
  function parseCameraRecords(raw) {
114
114
  if (!isRecordObject(raw)) return {};
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.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");
@@ -1,4 +1,4 @@
1
- import { Cr as EventCategory, En as storageOccupancyCapability, J as backupCapability, Qn as BaseAddon, Sr as toNodeId, Yt as mayWriteToLocation, g as DATABASE_SNAPSHOT_SUFFIX, hr as nodePin } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, J as backupCapability, Mn as storageOccupancyCapability, Qt as mayWriteToLocation, Sr as nodePin, ar as BaseAddon, g as DATABASE_SNAPSHOT_SUFFIX, kr as toNodeId } from "../../dist-pTfD_M-U.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";
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
7
  const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/calendars/calendar-color.ts
@@ -1,4 +1,4 @@
1
- import { $ as calendarsCapability, Qn as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-B7WRgEZY.mjs";
1
+ import { $ as calendarsCapability, ar as BaseAddon, p as CalendarPreferencesSchema } from "../../dist-pTfD_M-U.mjs";
2
2
  import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/calendars/calendar-color.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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
7
  let zod = require("zod");
8
8
  let _camstack_types_node = require("@camstack/types/node");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $t as motionCapability, A as MOTION_CLOSE_AFTER_MS, Cn as snapshotCapability, Cr as EventCategory, Jn as DeviceFeature, Ln as buildFfmpegArgs, On as streamCatalogCapability, Qn as BaseAddon, Xn as DeviceType, Xt as memoizePinnedFfmpeg, Zn as errMsg, b as DeclaredDevices, cr as createEvent, et as cameraGridLayoutCapability, fr as hydrateSchema, i as BaseDevice, pt as declarationOwnerNodeId, y as DERIVED_CAMERA_SILENCED_CAP_NAMES } from "../../dist-B7WRgEZY.mjs";
1
+ import { $t as memoizePinnedFfmpeg, A as MOTION_CLOSE_AFTER_MS, Ar as EventCategory, Pn as streamCatalogCapability, Wn as buildFfmpegArgs, ar as BaseAddon, b as DeclaredDevices, et as cameraGridLayoutCapability, hr as createEvent, i as BaseDevice, ir as errMsg, kn as snapshotCapability, mt as declarationOwnerNodeId, nn as motionCapability, rr as DeviceType, tr as DeviceFeature, y as DERIVED_CAMERA_SILENCED_CAP_NAMES, yr as hydrateSchema } from "../../dist-pTfD_M-U.mjs";
2
2
  import { z } from "zod";
3
3
  import { FfmpegProcess } from "@camstack/types/node";
4
4
  import { join } from "node:path";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CFVOy8VT.js");
7
- const require_composition_sources = require("../../composition-sources-CeO0K2cl.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
+ const require_composition_sources = require("../../composition-sources-CCU_KizO.js");
8
8
  let zod = require("zod");
9
9
  //#region src/builtins/shared/device-state-changed.ts
10
10
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -317,7 +317,7 @@ var ComposedDeviceSet = class {
317
317
  //#endregion
318
318
  //#region src/builtins/composer/composer-apply-waits.ts
319
319
  var INTEGRATION_WAIT = "waiting for the shared Blocks integration to reconcile";
320
- var STORE_NOT_LOADED = "the core_blocks store has not loaded — nothing is declared or withdrawn until it does (D49)";
320
+ var STORE_NOT_LOADED = "the core_blocks store has not loaded — nothing is declared or withdrawn until it does";
321
321
  var ApplyWaits = class {
322
322
  logger;
323
323
  /** Consecutive applies refused because `core_blocks` had not loaded: warned once per run. */
@@ -522,7 +522,7 @@ function degradedReason(released) {
522
522
  function heldReason(held) {
523
523
  return held.map((r) => {
524
524
  const path = r.item === void 0 ? r.path : require_dist.compositionItemFieldPath(r.item.arrayPath, r.item.key, r.path);
525
- return `held on its last value until its source answers (D49): ${r.cap}.${path} — ${r.reason}`;
525
+ return `held on its last value until its source answers: ${r.cap}.${path} — ${r.reason}`;
526
526
  }).join("; ");
527
527
  }
528
528
  /**
@@ -2530,10 +2530,10 @@ var ConfirmedSeed = class {
2530
2530
  * holds (before any release). Each is a `ConfirmedSeed`: an unread or a
2531
2531
  * first-empty answer waits, by name, for an agreeing read.
2532
2532
  */
2533
- var ROWS_UNREAD = "the composer's own device rows could not be read — nothing is declared or withdrawn until they are (D49)";
2534
- var ROWS_EMPTY_UNCONFIRMED = "the composer's own device rows read empty once — a cold registry answers the same, so nothing is declared or withdrawn until the next apply's read agrees (D49)";
2535
- var CLAIMS_NOT_LOADED = "the claims index has not loaded — nothing is claimed or released until it does (D49)";
2536
- var CLAIMS_EMPTY_UNCONFIRMED = "the claims index read empty once — nothing is claimed or released until the next apply's read agrees (D49)";
2533
+ var ROWS_UNREAD = "the composer's own device rows could not be read — nothing is declared or withdrawn until they are";
2534
+ var ROWS_EMPTY_UNCONFIRMED = "the composer's own device rows read empty once — a cold registry answers the same, so nothing is declared or withdrawn until the next apply's read agrees";
2535
+ var CLAIMS_NOT_LOADED = "the claims index has not loaded — nothing is claimed or released until it does";
2536
+ var CLAIMS_EMPTY_UNCONFIRMED = "the claims index read empty once — nothing is claimed or released until the next apply's read agrees";
2537
2537
  /** The rows the composer owns, read ONCE before its first withdrawal decision. */
2538
2538
  function composedRowSeed(deps) {
2539
2539
  return new ConfirmedSeed({
@@ -1,5 +1,5 @@
1
- import { Bn as composedDeviceStableId, Cr as EventCategory, Gn as createStatefulExpressionMemory, Hn as compositionItemFieldPath, In as COMPOSER_ADDON_ID, Kn as disarmRoseMemory, Ot as expressionContainsBuiltinCall, Qn as BaseAddon, Rn as cloneStatefulExpressionMemory, Tt as evaluateCompositionField, Un as compositionSliceKey, Vn as compositionFeatureEnabled, Wn as compositionSourceKey, Xn as DeviceType, Z as buildCapabilityLookup, Zn as errMsg, b as DeclaredDevices, cr as createEvent, i as BaseDevice, l as COMPOSED_ITEM_FIXED_FIELDS, nt as composerCapability, on as planComposition, qn as toExpressionValue, rt as compositionFieldKey, t as ALL_CAPABILITY_DEFINITIONS, zn as composedDeviceRef } from "../../dist-B7WRgEZY.mjs";
2
- import { n as normalizedNativeOwner } from "../../composition-sources-BBfqepyT.mjs";
1
+ import { $n as disarmRoseMemory, Ar as EventCategory, Et as evaluateCompositionField, Gn as cloneStatefulExpressionMemory, Jn as compositionFeatureEnabled, Kn as composedDeviceRef, Qn as createStatefulExpressionMemory, Un as COMPOSER_ADDON_ID, Xn as compositionSliceKey, Yn as compositionItemFieldPath, Z as buildCapabilityLookup, Zn as compositionSourceKey, ar as BaseAddon, b as DeclaredDevices, er as toExpressionValue, hr as createEvent, i as BaseDevice, ir as errMsg, it as compositionFieldKey, kt as expressionContainsBuiltinCall, l as COMPOSED_ITEM_FIXED_FIELDS, ln as planComposition, qn as composedDeviceStableId, rr as DeviceType, rt as composerCapability, t as ALL_CAPABILITY_DEFINITIONS } from "../../dist-pTfD_M-U.mjs";
2
+ import { n as normalizedNativeOwner } from "../../composition-sources-CHlfWHl6.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/builtins/shared/device-state-changed.ts
5
5
  /** Structural narrowing helper for untrusted bus payloads. */
@@ -312,7 +312,7 @@ var ComposedDeviceSet = class {
312
312
  //#endregion
313
313
  //#region src/builtins/composer/composer-apply-waits.ts
314
314
  var INTEGRATION_WAIT = "waiting for the shared Blocks integration to reconcile";
315
- var STORE_NOT_LOADED = "the core_blocks store has not loaded — nothing is declared or withdrawn until it does (D49)";
315
+ var STORE_NOT_LOADED = "the core_blocks store has not loaded — nothing is declared or withdrawn until it does";
316
316
  var ApplyWaits = class {
317
317
  logger;
318
318
  /** Consecutive applies refused because `core_blocks` had not loaded: warned once per run. */
@@ -517,7 +517,7 @@ function degradedReason(released) {
517
517
  function heldReason(held) {
518
518
  return held.map((r) => {
519
519
  const path = r.item === void 0 ? r.path : compositionItemFieldPath(r.item.arrayPath, r.item.key, r.path);
520
- return `held on its last value until its source answers (D49): ${r.cap}.${path} — ${r.reason}`;
520
+ return `held on its last value until its source answers: ${r.cap}.${path} — ${r.reason}`;
521
521
  }).join("; ");
522
522
  }
523
523
  /**
@@ -2525,10 +2525,10 @@ var ConfirmedSeed = class {
2525
2525
  * holds (before any release). Each is a `ConfirmedSeed`: an unread or a
2526
2526
  * first-empty answer waits, by name, for an agreeing read.
2527
2527
  */
2528
- var ROWS_UNREAD = "the composer's own device rows could not be read — nothing is declared or withdrawn until they are (D49)";
2529
- var ROWS_EMPTY_UNCONFIRMED = "the composer's own device rows read empty once — a cold registry answers the same, so nothing is declared or withdrawn until the next apply's read agrees (D49)";
2530
- var CLAIMS_NOT_LOADED = "the claims index has not loaded — nothing is claimed or released until it does (D49)";
2531
- var CLAIMS_EMPTY_UNCONFIRMED = "the claims index read empty once — nothing is claimed or released until the next apply's read agrees (D49)";
2528
+ var ROWS_UNREAD = "the composer's own device rows could not be read — nothing is declared or withdrawn until they are";
2529
+ var ROWS_EMPTY_UNCONFIRMED = "the composer's own device rows read empty once — a cold registry answers the same, so nothing is declared or withdrawn until the next apply's read agrees";
2530
+ var CLAIMS_NOT_LOADED = "the claims index has not loaded — nothing is claimed or released until it does";
2531
+ var CLAIMS_EMPTY_UNCONFIRMED = "the claims index read empty once — nothing is claimed or released until the next apply's read agrees";
2532
2532
  /** The rows the composer owns, read ONCE before its first withdrawal decision. */
2533
2533
  function composedRowSeed(deps) {
2534
2534
  return new ConfirmedSeed({
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.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 { Gt as logDestinationCapability, Qn as BaseAddon } from "../../dist-B7WRgEZY.mjs";
1
+ import { Jt as logDestinationCapability, ar as BaseAddon } from "../../dist-pTfD_M-U.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,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-CFVOy8VT.js");
4
- const require_composition_sources = require("../../composition-sources-CeO0K2cl.js");
3
+ const require_dist = require("../../dist-W_X44h-s.js");
4
+ const require_composition_sources = require("../../composition-sources-CCU_KizO.js");
5
5
  let node_crypto = require("node:crypto");
6
6
  let _camstack_types_node = require("@camstack/types/node");
7
7
  let node_fs_promises = require("node:fs/promises");
@@ -1,5 +1,5 @@
1
- import { Qn as BaseAddon, Wn as compositionSourceKey, Z as buildCapabilityLookup, Zn as errMsg, _t as describeComposableCaps, at as coreBlockAddonId, b as DeclaredDevices, ct as coreBlockSourceKind, d as CORE_BLOCKS_ADDON_ID, dn as replacedFieldKeys, en as normalizeCoreBlockWrite, f as CORE_BLOCK_ADDON_PREFIX, fr as hydrateSchema, it as compositionSourceRefs, jn as validateComposition, lt as coreBlocksCapability, m as CoreBlockSchema, mn as resolveCoreBlockFiles, on as planComposition, ot as coreBlockComposition, pn as resolveCoreBlockEntry, st as coreBlockIdFromAddonId, t as ALL_CAPABILITY_DEFINITIONS, u as COMPOSER_RUNNER_ID, zn as composedDeviceRef } from "../../dist-B7WRgEZY.mjs";
2
- import { t as describeCompositionSources } from "../../composition-sources-BBfqepyT.mjs";
1
+ import { Kn as composedDeviceRef, Ln as validateComposition, Z as buildCapabilityLookup, Zn as compositionSourceKey, _n as resolveCoreBlockFiles, ar as BaseAddon, at as compositionSourceRefs, b as DeclaredDevices, ct as coreBlockIdFromAddonId, d as CORE_BLOCKS_ADDON_ID, f as CORE_BLOCK_ADDON_PREFIX, gn as resolveCoreBlockEntry, ir as errMsg, ln as planComposition, lt as coreBlockSourceKind, m as CoreBlockSchema, mn as replacedFieldKeys, ot as coreBlockAddonId, rn as normalizeCoreBlockWrite, st as coreBlockComposition, t as ALL_CAPABILITY_DEFINITIONS, u as COMPOSER_RUNNER_ID, ut as coreBlocksCapability, vt as describeComposableCaps, yr as hydrateSchema } from "../../dist-pTfD_M-U.mjs";
2
+ import { t as describeCompositionSources } from "../../composition-sources-CHlfWHl6.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { customizationBlockName } from "@camstack/types/node";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-CFVOy8VT.js");
7
- const require_retired_settings_keys = require("../../retired-settings-keys-CRlTzxaS.js");
6
+ const require_dist = require("../../dist-W_X44h-s.js");
7
+ const require_retired_settings_keys = require("../../retired-settings-keys-jglEzgWR.js");
8
8
  let zod = require("zod");
9
9
  let node_crypto = require("node:crypto");
10
10
  let _camstack_types_node = require("@camstack/types/node");
@@ -4048,7 +4048,7 @@ async function applyGroupPatch(deps, deviceId, group) {
4048
4048
  tags: { deviceId },
4049
4049
  meta: { keys: retired }
4050
4050
  });
4051
- throw new Error(`[device-manager] ${retired.join(", ")} can no longer be saved from the settings section (D655) — reload the page and use the Extensions section`);
4051
+ throw new Error(`[device-manager] ${retired.join(", ")} can no longer be saved from the settings section — reload the page and use the Extensions section`);
4052
4052
  }
4053
4053
  const driverPatch = group.patch;
4054
4054
  if (Object.keys(driverPatch).length === 0) return;
@@ -4431,7 +4431,7 @@ function sourceOf(deviceId, byId) {
4431
4431
  deviceId,
4432
4432
  name: device.name,
4433
4433
  health: "unavailable",
4434
- detail: "A container is never a pick (D356): its children are linked in its place. Pick the children instead."
4434
+ detail: "A container is never a pick: its children are linked in its place. Pick the children instead."
4435
4435
  };
4436
4436
  return {
4437
4437
  deviceId,
@@ -8223,13 +8223,13 @@ function deepEqual(a, b) {
8223
8223
  var RuntimeStateRowUnreadError = class extends Error {
8224
8224
  deviceId;
8225
8225
  constructor(deviceId) {
8226
- super(`runtime-state row of device ${deviceId} could not be read — nothing written, a row this process has not read is never replaced (D677)`);
8226
+ super(`runtime-state row of device ${deviceId} could not be read — nothing written, a row this process has not read is never replaced`);
8227
8227
  this.deviceId = deviceId;
8228
8228
  this.name = "RuntimeStateRowUnreadError";
8229
8229
  }
8230
8230
  };
8231
- var ROW_UNREAD_REFUSAL_MESSAGE = "runtime-state row write refused — the row could not be read first, nothing written (D677)";
8232
- var ROW_DROPS_CAPS_MESSAGE = "runtime-state row write DROPS caps the stored row holds (D677)";
8231
+ var ROW_UNREAD_REFUSAL_MESSAGE = "runtime-state row write refused — the row could not be read first, nothing written";
8232
+ var ROW_DROPS_CAPS_MESSAGE = "runtime-state row write DROPS caps the stored row holds";
8233
8233
  function errorMessage$2(err) {
8234
8234
  return err instanceof Error ? err.message : String(err);
8235
8235
  }
@@ -8631,7 +8631,7 @@ var MirrorRowWriter = class MirrorRowWriter {
8631
8631
  * the owner alone — `nativeSlice` and `DeviceNativeShadowChanged`, a category
8632
8632
  * the public routers refuse (D224).
8633
8633
  */
8634
- var SEED_REFUSAL_MESSAGE = "runtime-state row unreadable — native write refused until it reads (D49)";
8634
+ var SEED_REFUSAL_MESSAGE = "runtime-state row unreadable — native write refused until it reads";
8635
8635
  function errorMessage$1(err) {
8636
8636
  return err instanceof Error ? err.message : String(err);
8637
8637
  }
@@ -9353,7 +9353,7 @@ var FieldClaimsIndex = class {
9353
9353
  /** The three-way read (D651): a failed read is a REASON, never an empty index. */
9354
9354
  async readBlob(settings) {
9355
9355
  if (settings.readAddonStoreResult === void 0) {
9356
- this.notLoadedReason = "this settings view predates the three-way addon-store read (D651)";
9356
+ this.notLoadedReason = "this settings view predates the three-way addon-store read";
9357
9357
  return false;
9358
9358
  }
9359
9359
  let read;
@@ -1,5 +1,5 @@
1
- import { Bt as legacyAutoLinkIds, C as FieldClaimModeSchema, Cr as EventCategory, Ct as enumerateItemArrayFields, D as LocationIconIdSchema, Dt as expandContainer, I as STREAM_PROFILE_META, Jn as DeviceFeature, Mt as formatMinutes, Q as buildStreamParamsConfigSchema, Qn as BaseAddon, Sn as siteZoneKey, Wt as locationIconKey, Xn as DeviceType, Yn as DeviceRole, Zn as errMsg, _n as runtimeStatePolicyFor, bt as deviceStateCapability, c as CAP_NAMES_WITH_STATUS, ht as defineExtensionSlotProvider, in as parseStreamParamsFormPatch, ir as WELL_KNOWN_TAB_MAP, k as MINUTES_PER_DAY, o as CAMERA_SWITCH_ORDER, pr as isDeviceConfigCap, t as ALL_CAPABILITY_DEFINITIONS, tn as normalizeUnit, ut as createDeviceExtensionProvider, v as DAY_NAMES, vt as deviceExtensionCapability, w as FieldClaimSchema, wt as enumerateSchemaFields, x as DeviceStatusSchema, xr as sleep$1, xt as deviceStatusCapability, yt as deviceManagerCapability } from "../../dist-B7WRgEZY.mjs";
2
- import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-DKRjfz0U.mjs";
1
+ import { Ar as EventCategory, C as FieldClaimModeSchema, Cn as runtimeStatePolicyFor, D as LocationIconIdSchema, I as STREAM_PROFILE_META, Nt as formatMinutes, On as siteZoneKey, Or as sleep$1, Ot as expandContainer, Q as buildStreamParamsConfigSchema, St as deviceStatusCapability, Tt as enumerateSchemaFields, Ut as legacyAutoLinkIds, ar as BaseAddon, br as isDeviceConfigCap, bt as deviceManagerCapability, c as CAP_NAMES_WITH_STATUS, dr as WELL_KNOWN_TAB_MAP, dt as createDeviceExtensionProvider, gt as defineExtensionSlotProvider, in as normalizeUnit, ir as errMsg, k as MINUTES_PER_DAY, nr as DeviceRole, o as CAMERA_SWITCH_ORDER, qt as locationIconKey, rr as DeviceType, sn as parseStreamParamsFormPatch, t as ALL_CAPABILITY_DEFINITIONS, tr as DeviceFeature, v as DAY_NAMES, w as FieldClaimSchema, wt as enumerateItemArrayFields, x as DeviceStatusSchema, xt as deviceStateCapability, yt as deviceExtensionCapability } from "../../dist-pTfD_M-U.mjs";
2
+ import { n as purgeRetiredSettingsRows } from "../../retired-settings-keys-CK_ifret.mjs";
3
3
  import { z } from "zod";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { canonicalDeviceFingerprint } from "@camstack/types/node";
@@ -4043,7 +4043,7 @@ async function applyGroupPatch(deps, deviceId, group) {
4043
4043
  tags: { deviceId },
4044
4044
  meta: { keys: retired }
4045
4045
  });
4046
- throw new Error(`[device-manager] ${retired.join(", ")} can no longer be saved from the settings section (D655) — reload the page and use the Extensions section`);
4046
+ throw new Error(`[device-manager] ${retired.join(", ")} can no longer be saved from the settings section — reload the page and use the Extensions section`);
4047
4047
  }
4048
4048
  const driverPatch = group.patch;
4049
4049
  if (Object.keys(driverPatch).length === 0) return;
@@ -4426,7 +4426,7 @@ function sourceOf(deviceId, byId) {
4426
4426
  deviceId,
4427
4427
  name: device.name,
4428
4428
  health: "unavailable",
4429
- detail: "A container is never a pick (D356): its children are linked in its place. Pick the children instead."
4429
+ detail: "A container is never a pick: its children are linked in its place. Pick the children instead."
4430
4430
  };
4431
4431
  return {
4432
4432
  deviceId,
@@ -8218,13 +8218,13 @@ function deepEqual(a, b) {
8218
8218
  var RuntimeStateRowUnreadError = class extends Error {
8219
8219
  deviceId;
8220
8220
  constructor(deviceId) {
8221
- super(`runtime-state row of device ${deviceId} could not be read — nothing written, a row this process has not read is never replaced (D677)`);
8221
+ super(`runtime-state row of device ${deviceId} could not be read — nothing written, a row this process has not read is never replaced`);
8222
8222
  this.deviceId = deviceId;
8223
8223
  this.name = "RuntimeStateRowUnreadError";
8224
8224
  }
8225
8225
  };
8226
- var ROW_UNREAD_REFUSAL_MESSAGE = "runtime-state row write refused — the row could not be read first, nothing written (D677)";
8227
- var ROW_DROPS_CAPS_MESSAGE = "runtime-state row write DROPS caps the stored row holds (D677)";
8226
+ var ROW_UNREAD_REFUSAL_MESSAGE = "runtime-state row write refused — the row could not be read first, nothing written";
8227
+ var ROW_DROPS_CAPS_MESSAGE = "runtime-state row write DROPS caps the stored row holds";
8228
8228
  function errorMessage$2(err) {
8229
8229
  return err instanceof Error ? err.message : String(err);
8230
8230
  }
@@ -8626,7 +8626,7 @@ var MirrorRowWriter = class MirrorRowWriter {
8626
8626
  * the owner alone — `nativeSlice` and `DeviceNativeShadowChanged`, a category
8627
8627
  * the public routers refuse (D224).
8628
8628
  */
8629
- var SEED_REFUSAL_MESSAGE = "runtime-state row unreadable — native write refused until it reads (D49)";
8629
+ var SEED_REFUSAL_MESSAGE = "runtime-state row unreadable — native write refused until it reads";
8630
8630
  function errorMessage$1(err) {
8631
8631
  return err instanceof Error ? err.message : String(err);
8632
8632
  }
@@ -9348,7 +9348,7 @@ var FieldClaimsIndex = class {
9348
9348
  /** The three-way read (D651): a failed read is a REASON, never an empty index. */
9349
9349
  async readBlob(settings) {
9350
9350
  if (settings.readAddonStoreResult === void 0) {
9351
- this.notLoadedReason = "this settings view predates the three-way addon-store read (D651)";
9351
+ this.notLoadedReason = "this settings view predates the three-way addon-store read";
9352
9352
  return false;
9353
9353
  }
9354
9354
  let read;
@@ -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-CFVOy8VT.js");
6
+ const require_dist = require("../../dist-W_X44h-s.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 { Gt as logDestinationCapability, Qn as BaseAddon } from "../../dist-B7WRgEZY.mjs";
1
+ import { Jt as logDestinationCapability, ar as BaseAddon } from "../../dist-pTfD_M-U.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-CFVOy8VT.js");
3
+ const require_dist = require("../../dist-W_X44h-s.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 { Cr as EventCategory, P as RecordingStatusSchema, Qn as BaseAddon, Zn as errMsg, cr as createEvent, j as RECORDING_SOURCE_CAMSTACK_ADDON } from "../../dist-B7WRgEZY.mjs";
1
+ import { Ar as EventCategory, P as RecordingStatusSchema, ar as BaseAddon, hr as createEvent, ir as errMsg, j as RECORDING_SOURCE_CAMSTACK_ADDON } from "../../dist-pTfD_M-U.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";
@@ -0,0 +1,27 @@
1
+ import { IScopedLogger } from '@camstack/types';
2
+ import { AdminSeedOutcome, EnsureAdminOptions } from '../../auth/user-manager.js';
3
+ /** The trigger's name, at the root of the node's data directory. */
4
+ export declare const ADMIN_PASSWORD_RESET_TRIGGER = "RESET_ADMIN_PASSWORD";
5
+ /** The file operations the boot step needs — injectable for tests. */
6
+ export interface TriggerFs {
7
+ exists(filePath: string): boolean;
8
+ remove(filePath: string): void;
9
+ }
10
+ /** The slice of `UserManager` the boot step drives. */
11
+ export interface AdminAccountManager {
12
+ ensureAdminExists(options?: EnsureAdminOptions): Promise<AdminSeedOutcome>;
13
+ hasPassword(username: string, password: string): Promise<boolean>;
14
+ }
15
+ export interface AdminAccountBootInput {
16
+ readonly users: AdminAccountManager;
17
+ /** `ctx.nodeDataDir` — where the operator drops the trigger. */
18
+ readonly dataDir: string;
19
+ readonly fs: TriggerFs;
20
+ readonly logger: IScopedLogger;
21
+ }
22
+ export interface AdminAccountBootResult {
23
+ readonly outcome: AdminSeedOutcome;
24
+ /** The admin still signs in with {@link DEFAULT_ADMIN_PASSWORD}. */
25
+ readonly usesDefaultPassword: boolean;
26
+ }
27
+ export declare function reconcileAdminAccountAtBoot(input: AdminAccountBootInput): Promise<AdminAccountBootResult>;
@@ -1,8 +1,9 @@
1
1
  import { SettingsStoreClient } from '@camstack/types';
2
2
  /**
3
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"
4
+ * write="an operator creates a user, or `ensureAdminExists` seeds the configured
5
+ * admin on first boot (or resets its password on the operator's one-shot
6
+ * RESET_ADMIN_PASSWORD trigger); updated on scope, isAdmin and password edits"
6
7
  * retention="none — a row goes only when an operator deletes the user. A
7
8
  * `declareCollection` that adds a PK/UNIQUE/NOT-NULL-without-default column
8
9
  * REBUILDS the table: every account is wiped and only the configured admin