@camstack/server 1.2.592 → 1.2.594

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 (256) hide show
  1. package/dist/addon-root-inventory.js +11 -50
  2. package/dist/agent/addon-scan.js +6 -44
  3. package/dist/agent/agent-addon-runtime.js +3 -8
  4. package/dist/agent/agent-addon-updates.js +12 -52
  5. package/dist/agent/agent-cap-dispatch-service.js +3 -5
  6. package/dist/agent/agent-config.js +7 -42
  7. package/dist/agent/agent-deploy-swap.js +5 -41
  8. package/dist/agent/agent-group-runner.js +8 -47
  9. package/dist/agent/agent-http-auth.js +10 -22
  10. package/dist/agent/agent-http.js +69 -115
  11. package/dist/agent/agent-hub-addon-update.js +10 -16
  12. package/dist/agent/agent-hub-registration.js +4 -7
  13. package/dist/agent/agent-infra-capabilities.js +5 -9
  14. package/dist/agent/agent-json-file.js +5 -42
  15. package/dist/agent/agent-mesh-gate.js +5 -8
  16. package/dist/agent/agent-node-certificates.js +25 -28
  17. package/dist/agent/agent-pairing-local.js +10 -47
  18. package/dist/agent/agent-pairing-routes.js +16 -20
  19. package/dist/agent/agent-pairing-store.js +18 -58
  20. package/dist/agent/agent-reconnect.js +1 -4
  21. package/dist/agent/agent-service.js +42 -78
  22. package/dist/agent/agent-sniffing-listener.js +11 -48
  23. package/dist/agent/agent-undeploy.js +5 -41
  24. package/dist/agent/agent-update-routes.js +14 -19
  25. package/dist/agent/agent-update-service.js +38 -80
  26. package/dist/agent/apply-model-distribution.js +1 -4
  27. package/dist/agent/apply-stage-dev-uploads.js +6 -9
  28. package/dist/agent/derive-hub-url.js +3 -8
  29. package/dist/agent/fetch-bundle-from-hub.js +6 -9
  30. package/dist/agent/hubs-found.js +6 -43
  31. package/dist/agent/infra-boot-guard.js +1 -4
  32. package/dist/agent/infra-boot-plan.js +2 -6
  33. package/dist/agent/main.js +158 -186
  34. package/dist/agent/register-agent-cap-dispatch.js +3 -6
  35. package/dist/agent/serial-queue.js +2 -7
  36. package/dist/agent-status-page.js +1 -4
  37. package/dist/api/addon-upload.js +22 -61
  38. package/dist/api/agent-addon-delivery.js +6 -11
  39. package/dist/api/auth-whoami.js +1 -4
  40. package/dist/api/backup-download-pump.js +5 -9
  41. package/dist/api/backup-download.js +7 -10
  42. package/dist/api/core/addon-settings.router.js +16 -19
  43. package/dist/api/core/agent-pairing.router.js +76 -79
  44. package/dist/api/core/agents.router.js +21 -24
  45. package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
  46. package/dist/api/core/auth-device-cert.procedures.js +62 -67
  47. package/dist/api/core/auth-limits.js +16 -25
  48. package/dist/api/core/auth-reauth.procedures.js +32 -37
  49. package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
  50. package/dist/api/core/auth-sessions.procedures.js +52 -56
  51. package/dist/api/core/auth.router.js +300 -304
  52. package/dist/api/core/cap-providers.js +74 -121
  53. package/dist/api/core/capabilities.router.js +34 -37
  54. package/dist/api/core/capability-preference-writes.js +10 -17
  55. package/dist/api/core/certificates.router.js +106 -109
  56. package/dist/api/core/cluster-nodes.router.js +15 -18
  57. package/dist/api/core/collection-preference.js +2 -6
  58. package/dist/api/core/event-bus-proxy.router.js +34 -37
  59. package/dist/api/core/failure-contributions.js +4 -8
  60. package/dist/api/core/hwaccel.router.js +17 -20
  61. package/dist/api/core/integration-secrets.js +8 -12
  62. package/dist/api/core/lifecycle-job-runner.js +13 -49
  63. package/dist/api/core/live-events.router.js +29 -32
  64. package/dist/api/core/load-contributions.js +4 -8
  65. package/dist/api/core/logging-settings.js +30 -43
  66. package/dist/api/core/logs.router.js +40 -43
  67. package/dist/api/core/notifications.router.js +15 -18
  68. package/dist/api/core/public-event-filter.js +4 -8
  69. package/dist/api/core/repl.router.js +18 -21
  70. package/dist/api/core/request-census-settings.js +11 -16
  71. package/dist/api/core/server-management.provider.js +1 -4
  72. package/dist/api/core/server-name.js +9 -17
  73. package/dist/api/core/site-location.js +16 -24
  74. package/dist/api/core/stream-probe.router.js +21 -24
  75. package/dist/api/core/system-events.router.js +23 -26
  76. package/dist/api/cors/cors-policy.js +20 -29
  77. package/dist/api/cors/register-cors-policy.js +9 -14
  78. package/dist/api/deploy-stage-registry.js +6 -10
  79. package/dist/api/dev-uploads-bundle.js +12 -50
  80. package/dist/api/health/adaptive-probe.routes.js +9 -13
  81. package/dist/api/health/health.routes.js +8 -13
  82. package/dist/api/hub-cluster-url.js +3 -9
  83. package/dist/api/model-distributor.js +12 -50
  84. package/dist/api/oauth2/consent-page.js +10 -13
  85. package/dist/api/oauth2/oauth2-routes.js +17 -25
  86. package/dist/api/oauth2/private-host.js +1 -4
  87. package/dist/api/server-upload-propagate.js +15 -51
  88. package/dist/api/server-upload.js +13 -50
  89. package/dist/api/sse-no-compression.js +1 -4
  90. package/dist/api/static/frame-policy.js +4 -9
  91. package/dist/api/static/precompressed-asset.js +15 -57
  92. package/dist/api/static/spa-mount.js +8 -47
  93. package/dist/api/static/spa-static.js +5 -12
  94. package/dist/api/tarball-manifest.js +7 -44
  95. package/dist/api/trpc/cap-mount-helpers.js +7 -12
  96. package/dist/api/trpc/cap-route-error-formatter.js +10 -13
  97. package/dist/api/trpc/cap-router-runtime.js +40 -51
  98. package/dist/api/trpc/client-ip.js +9 -20
  99. package/dist/api/trpc/core-cap-bridge.js +32 -42
  100. package/dist/api/trpc/device-collection-dispatch.js +23 -27
  101. package/dist/api/trpc/device-config-secret-redaction.js +24 -40
  102. package/dist/api/trpc/generated-cap-mounts.js +219 -221
  103. package/dist/api/trpc/generated-cap-routers.js +4878 -4726
  104. package/dist/api/trpc/http-request-census-hook.js +8 -11
  105. package/dist/api/trpc/http-request-census.js +34 -41
  106. package/dist/api/trpc/http-request-census.singleton.js +4 -8
  107. package/dist/api/trpc/localized-schema-paths.js +1 -4
  108. package/dist/api/trpc/principal-visibility.js +14 -22
  109. package/dist/api/trpc/remote-addon-update-grant.js +1 -4
  110. package/dist/api/trpc/scope-access.js +10 -15
  111. package/dist/api/trpc/server-provided-caps.js +3 -7
  112. package/dist/api/trpc/share-view-access.js +6 -14
  113. package/dist/api/trpc/trpc-error-device-tags.js +3 -6
  114. package/dist/api/trpc/trpc-error-principal.js +2 -6
  115. package/dist/api/trpc/trpc.context.js +20 -25
  116. package/dist/api/trpc/trpc.middleware.js +38 -46
  117. package/dist/api/trpc/trpc.router.js +58 -99
  118. package/dist/api/trpc/user-error.js +5 -8
  119. package/dist/api/trpc/ws-request-census.js +17 -24
  120. package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
  121. package/dist/api/upload-auth.js +5 -9
  122. package/dist/auth/addon-route-jwt-gate.js +4 -7
  123. package/dist/auth/addon-route-share-gate.js +7 -12
  124. package/dist/auth/app-confirm-page.js +17 -22
  125. package/dist/auth/app-confirm-routes.js +26 -31
  126. package/dist/auth/app-confirmations.js +7 -44
  127. package/dist/auth/app-page-shell.js +17 -30
  128. package/dist/auth/app-page-strings.js +11 -17
  129. package/dist/auth/app-passkey-page.js +16 -21
  130. package/dist/auth/app-passkey-routes.js +37 -41
  131. package/dist/auth/app-refused-route.js +13 -18
  132. package/dist/auth/auth-network-policy.js +11 -15
  133. package/dist/auth/auth-provider-gate.js +4 -9
  134. package/dist/auth/auth-rate-limit.js +3 -7
  135. package/dist/auth/client-address.js +6 -9
  136. package/dist/auth/device-enroll-proofs.js +6 -43
  137. package/dist/auth/external-link-intents.js +3 -7
  138. package/dist/auth/hub-sessions.js +6 -12
  139. package/dist/auth/native-link-completions.js +7 -11
  140. package/dist/auth/native-return.js +9 -13
  141. package/dist/auth/passkey-provider.js +26 -32
  142. package/dist/auth/second-factors.js +6 -10
  143. package/dist/auth/session-connections.js +6 -12
  144. package/dist/auth/session-cookie.js +12 -23
  145. package/dist/auth/session-lifetimes.js +8 -12
  146. package/dist/auth/session-mint.js +4 -11
  147. package/dist/auth/sso-finish-app.js +13 -16
  148. package/dist/auth/sso-finish-deps.js +21 -27
  149. package/dist/auth/sso-finish.js +28 -38
  150. package/dist/auth/sso-routes.js +22 -25
  151. package/dist/auth/used-bridge-ids.js +1 -5
  152. package/dist/boot/boot-config.js +16 -55
  153. package/dist/boot/init-sequence.js +1 -4
  154. package/dist/boot/integration-id-backfill.js +3 -8
  155. package/dist/boot/platform-keychain-key.js +5 -42
  156. package/dist/boot/post-boot.service.js +14 -18
  157. package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
  158. package/dist/boot/retired-public-url-env.js +4 -8
  159. package/dist/bootstrap-packages.js +1 -4
  160. package/dist/closure-node-modules.js +2 -38
  161. package/dist/closure-patches/patch-reach.json +6 -2
  162. package/dist/core/addon/addon-call-gateway.js +1 -5
  163. package/dist/core/addon/addon-package.service.js +83 -123
  164. package/dist/core/addon/addon-process-view.js +2 -6
  165. package/dist/core/addon/addon-realign-plan.js +1 -4
  166. package/dist/core/addon/addon-registry.service.js +254 -197
  167. package/dist/core/addon/addon-row-manifest.js +1 -4
  168. package/dist/core/addon/addon-search.service.js +3 -7
  169. package/dist/core/addon/addon-settings-provider.js +1 -3
  170. package/dist/core/addon/addon-uninstall.js +4 -11
  171. package/dist/core/addon/addon.tokens.js +2 -5
  172. package/dist/core/addon/device-meta-mirror.js +8 -13
  173. package/dist/core/addon/forked-custom-actions.js +6 -11
  174. package/dist/core/addon/integration-visibility.js +3 -6
  175. package/dist/core/addon/materialize-route-path.js +1 -4
  176. package/dist/core/addon/package-dir-utils.js +8 -45
  177. package/dist/core/addon/prune-misplaced-addons.js +5 -43
  178. package/dist/core/addon/runner-convergence.js +1 -4
  179. package/dist/core/addon/runner-serialization.js +1 -4
  180. package/dist/core/addon/runner-spawn-fanout.js +3 -8
  181. package/dist/core/addon/settings-door-wiring.js +5 -8
  182. package/dist/core/addon/single-flight-refresh.js +1 -4
  183. package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
  184. package/dist/core/addon-pages/addon-pages.service.js +3 -40
  185. package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
  186. package/dist/core/agent/agent-addon-backfill.js +9 -17
  187. package/dist/core/agent/agent-delivery-ledger.js +3 -7
  188. package/dist/core/agent/agent-liveness-event.js +2 -6
  189. package/dist/core/agent/agent-pairing-http.js +41 -45
  190. package/dist/core/agent/agent-registry.service.js +53 -92
  191. package/dist/core/agent/cluster-node-history-mirror.js +3 -7
  192. package/dist/core/agent/cluster-node-history-store.js +113 -58
  193. package/dist/core/agent/hub-agent-pairing.js +1 -5
  194. package/dist/core/agent/node-certificates-client.js +3 -6
  195. package/dist/core/agent/node-directory.js +1 -4
  196. package/dist/core/app-links/well-known-app-links.js +2 -6
  197. package/dist/core/auth/auth.service.js +3 -8
  198. package/dist/core/auth/handoff-code.service.js +11 -49
  199. package/dist/core/auth/record-kinds.js +35 -0
  200. package/dist/core/auth/share-token.service.js +174 -122
  201. package/dist/core/capability/capability.service.js +1 -5
  202. package/dist/core/config/config.schema.js +1 -6
  203. package/dist/core/config/config.service.js +2 -6
  204. package/dist/core/events/event-bus.service.js +3 -7
  205. package/dist/core/feature/feature.service.js +2 -6
  206. package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
  207. package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
  208. package/dist/core/logging/log-ring-buffer.js +1 -5
  209. package/dist/core/logging/logging.service.js +5 -9
  210. package/dist/core/logging/scoped-logger.js +1 -5
  211. package/dist/core/moleculer/agent-readiness-pull.js +1 -4
  212. package/dist/core/moleculer/agent-registration-request.js +3 -7
  213. package/dist/core/moleculer/cap-call-fn.js +39 -5
  214. package/dist/core/moleculer/cap-route-authority.js +3 -8
  215. package/dist/core/moleculer/hub-mesh-guard.js +5 -9
  216. package/dist/core/moleculer/moleculer.service.js +108 -119
  217. package/dist/core/network/network-quality.service.js +2 -6
  218. package/dist/core/notification/notification-wrapper.service.js +3 -7
  219. package/dist/core/notification/toast-wrapper.service.js +3 -7
  220. package/dist/core/provider/provider.tokens.js +1 -4
  221. package/dist/core/repl/repl-engine.service.js +4 -8
  222. package/dist/core/runner-health/runner-boot-check.js +7 -15
  223. package/dist/core/runner-health/update-preflight.js +9 -14
  224. package/dist/core/server-update/server-update.service.js +12 -49
  225. package/dist/core/server-update/system-apply-closure-patches.js +6 -42
  226. package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
  227. package/dist/core/server-update/system-exec-npm.js +2 -5
  228. package/dist/core/storage/fs-storage-backend.js +1 -5
  229. package/dist/core/storage/storage-location-manager.js +1 -5
  230. package/dist/core/storage/storage.service.js +2 -6
  231. package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
  232. package/dist/core/streaming/stream-probe.service.js +12 -16
  233. package/dist/core/streaming/ttl-cache.js +1 -5
  234. package/dist/core/topology/topology-emitter.service.js +19 -23
  235. package/dist/core/update-availability-emitter.js +3 -7
  236. package/dist/core/update-availability-store.js +8 -45
  237. package/dist/core/updates/agent-installed-packages.js +5 -9
  238. package/dist/core/updates/restart-marker.js +3 -8
  239. package/dist/core/updates/update-check-scheduler.js +13 -18
  240. package/dist/core/updates/wrapper-update-checker.js +3 -7
  241. package/dist/first-boot-addon-plan.js +2 -6
  242. package/dist/framework-nodepath.js +2 -38
  243. package/dist/i18n/request-lang.js +7 -11
  244. package/dist/launcher.js +30 -65
  245. package/dist/lifecycle-journal-path.js +2 -38
  246. package/dist/main.js +287 -324
  247. package/dist/manual-boot.js +120 -157
  248. package/dist/node-role.js +1 -4
  249. package/dist/package-inventory.js +7 -48
  250. package/dist/pending-restore.js +7 -43
  251. package/dist/single-copy-cleanup-runner.js +9 -45
  252. package/dist/single-copy-cleanup.js +7 -15
  253. package/dist/sqlite-restore.js +9 -48
  254. package/dist/starter.js +4 -39
  255. package/dist/ui-serving/lazy-ui-serving.js +3 -39
  256. package/package.json +13 -13
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Core-capability mesh bridge.
4
3
  *
@@ -17,22 +16,13 @@
17
16
  * service mounted on the hub node, `brokerTransportLink` resolves and
18
17
  * routes the call exactly like any addon-provided cap.
19
18
  */
20
- Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.REMOTE_PRIVILEGE_LOG_ONLY = exports.REMOTE_UPDATE_PACKAGE_PATH = exports.REMOTE_PRIVILEGE_ALLOWLIST = exports.CORE_CAP_REMOTE_FORBIDDEN_TYPE = exports.REMOTE_DENIED_NAMESPACES = void 0;
22
- exports.setRemotePrivilegeLogSink = setRemotePrivilegeLogSink;
23
- exports.__resetRemotePrivilegeObservationForTests = __resetRemotePrivilegeObservationForTests;
24
- exports.observeRemotePrivilege = observeRemotePrivilege;
25
- exports.observeRemotePrivilegeRefused = observeRemotePrivilegeRefused;
26
- exports.isCoreServiceCapName = isCoreServiceCapName;
27
- exports.describeMeshOrigin = describeMeshOrigin;
28
- exports.buildCoreCapService = buildCoreCapService;
29
- const system_1 = require("@camstack/system");
30
- const moleculer_1 = require("moleculer");
31
- const remote_addon_update_grant_js_1 = require("./remote-addon-update-grant.js");
32
- const http_request_census_singleton_js_1 = require("./http-request-census.singleton.js");
33
- const server_provided_caps_js_1 = require("./server-provided-caps.js");
34
- const trpc_context_js_1 = require("./trpc.context.js");
35
- const trpc_middleware_js_1 = require("./trpc.middleware.js");
19
+ import { createCoreCapService } from '@camstack/system';
20
+ import { Errors } from 'moleculer';
21
+ import { authorizeRemoteUpdatePackage, } from './remote-addon-update-grant.js';
22
+ import { getHttpRequestCensus } from './http-request-census.singleton.js';
23
+ import { HUB_SERVICE_CAP_NAMES, capNameToNamespace } from './server-provided-caps.js';
24
+ import { createMeshTrpcContext } from './trpc.context.js';
25
+ import { createCallerFactory } from './trpc.middleware.js';
36
26
  /**
37
27
  * appRouter namespaces that back the CORE API surface and must be
38
28
  * reachable cross-process: every server-provided hub-service cap
@@ -54,7 +44,7 @@ const trpc_middleware_js_1 = require("./trpc.middleware.js");
54
44
  */
55
45
  const CORE_NAMESPACES = new Set([
56
46
  // Service-backed cap routers (no addon provider) — derived, never copied.
57
- ...server_provided_caps_js_1.HUB_SERVICE_CAP_NAMES.map(server_provided_caps_js_1.capNameToNamespace),
47
+ ...HUB_SERVICE_CAP_NAMES.map(capNameToNamespace),
58
48
  // Hand-written single-impl core routers.
59
49
  'capabilities',
60
50
  'notifications',
@@ -71,18 +61,18 @@ const CORE_NAMESPACES = new Set([
71
61
  * (they read their own settings through the settings door), so refusing them
72
62
  * to an agent costs nothing and takes them off the LAN.
73
63
  */
74
- exports.REMOTE_DENIED_NAMESPACES = new Set([
64
+ export const REMOTE_DENIED_NAMESPACES = new Set([
75
65
  'logs',
76
66
  'addonSettingsRaw',
77
67
  ]);
78
68
  /** Moleculer error `type` of a bridged call another node may not make. */
79
- exports.CORE_CAP_REMOTE_FORBIDDEN_TYPE = 'CORE_CAP_REMOTE_FORBIDDEN';
69
+ export const CORE_CAP_REMOTE_FORBIDDEN_TYPE = 'CORE_CAP_REMOTE_FORBIDDEN';
80
70
  /**
81
71
  * Hub-core procedure paths another node may call after {@link REMOTE_DENIED_NAMESPACES}.
82
72
  * Seeded from armed transport census on the live hub (2026-10): remote agents
83
73
  * (`mesh:<agent>`) called none of these; hub runners used this surface only.
84
74
  */
85
- exports.REMOTE_PRIVILEGE_ALLOWLIST = new Set([
75
+ export const REMOTE_PRIVILEGE_ALLOWLIST = new Set([
86
76
  'addons.listCapabilityProviders',
87
77
  'nodes.topology',
88
78
  'integrations.getByAddonId',
@@ -92,20 +82,20 @@ exports.REMOTE_PRIVILEGE_ALLOWLIST = new Set([
92
82
  'system.getSiteLocation',
93
83
  ]);
94
84
  /** The one path outside the allowlist a node may call, under {@link authorizeRemoteUpdatePackage}. */
95
- exports.REMOTE_UPDATE_PACKAGE_PATH = 'addons.updatePackage';
85
+ export const REMOTE_UPDATE_PACKAGE_PATH = 'addons.updatePackage';
96
86
  /**
97
87
  * When true, remote bridged calls outside {@link REMOTE_PRIVILEGE_ALLOWLIST} are
98
88
  * logged once per `(nodeId, path)` per process — still admin, not refused.
99
89
  */
100
- exports.REMOTE_PRIVILEGE_LOG_ONLY = false;
90
+ export const REMOTE_PRIVILEGE_LOG_ONLY = false;
101
91
  let remotePrivilegeLogSink = null;
102
92
  /** Attach the warn sink used by {@link observeRemotePrivilege}. */
103
- function setRemotePrivilegeLogSink(sink) {
93
+ export function setRemotePrivilegeLogSink(sink) {
104
94
  remotePrivilegeLogSink = sink;
105
95
  }
106
96
  const remotePrivilegeObserved = new Set();
107
97
  /** Clears dedupe state and the sink — tests only. */
108
- function __resetRemotePrivilegeObservationForTests() {
98
+ export function __resetRemotePrivilegeObservationForTests() {
109
99
  remotePrivilegeObserved.clear();
110
100
  remotePrivilegeLogSink = null;
111
101
  }
@@ -125,8 +115,8 @@ function warnRemotePrivilegeOnce(nodeId, path, message) {
125
115
  * One warn per `(nodeId, path)` while {@link REMOTE_PRIVILEGE_LOG_ONLY} is on.
126
116
  * Call only after {@link REMOTE_DENIED_NAMESPACES} has passed.
127
117
  */
128
- function observeRemotePrivilege(nodeId, path) {
129
- if (!exports.REMOTE_PRIVILEGE_LOG_ONLY)
118
+ export function observeRemotePrivilege(nodeId, path) {
119
+ if (!REMOTE_PRIVILEGE_LOG_ONLY)
130
120
  return;
131
121
  warnRemotePrivilegeOnce(nodeId, path, `mesh privilege: node:${nodeId} called ${path} (log-only; still allowed)`);
132
122
  }
@@ -134,7 +124,7 @@ function observeRemotePrivilege(nodeId, path) {
134
124
  * One warn per `(nodeId, path)` when enforcement refuses a path not on
135
125
  * {@link REMOTE_PRIVILEGE_ALLOWLIST}. Call immediately before throwing.
136
126
  */
137
- function observeRemotePrivilegeRefused(nodeId, path) {
127
+ export function observeRemotePrivilegeRefused(nodeId, path) {
138
128
  warnRemotePrivilegeOnce(nodeId, path, `mesh privilege: node:${nodeId} called ${path} (refused; not on grant)`);
139
129
  }
140
130
  /**
@@ -162,7 +152,7 @@ const CORE_CAP_NAMES = new Set([
162
152
  * already-maintained {@link CORE_NAMESPACES} — a new addon cap is covered with
163
153
  * zero changes here.
164
154
  */
165
- function isCoreServiceCapName(capName) {
155
+ export function isCoreServiceCapName(capName) {
166
156
  return CORE_CAP_NAMES.has(capName);
167
157
  }
168
158
  function isProcedureNode(value) {
@@ -222,7 +212,7 @@ function countMeshCall(census, path, origin) {
222
212
  * principal. Never a token: there is none, the mesh context is trusted by
223
213
  * construction (`createMeshTrpcContext`).
224
214
  */
225
- function describeMeshOrigin(origin) {
215
+ export function describeMeshOrigin(origin) {
226
216
  const node = origin.nodeId ?? 'unknown';
227
217
  return origin.caller === null ? `mesh:${node}` : `mesh:${node} via ${origin.caller}`;
228
218
  }
@@ -251,13 +241,13 @@ function resolveInvoker(caller, path) {
251
241
  * Each call runs under a principal naming its origin (D802): `mesh` for the
252
242
  * hub's own runners, `node:<nodeId>` for another node.
253
243
  */
254
- function buildCoreCapService(appRouter, census = (0, http_request_census_singleton_js_1.getHttpRequestCensus)(), options = {}) {
255
- const callerFactory = (0, trpc_middleware_js_1.createCallerFactory)(appRouter);
244
+ export function buildCoreCapService(appRouter, census = getHttpRequestCensus(), options = {}) {
245
+ const callerFactory = createCallerFactory(appRouter);
256
246
  const callers = new Map();
257
247
  const callerFor = (principal) => {
258
248
  let caller = callers.get(principal);
259
249
  if (caller === undefined) {
260
- caller = callerFactory((0, trpc_context_js_1.createMeshTrpcContext)(principal));
250
+ caller = callerFactory(createMeshTrpcContext(principal));
261
251
  callers.set(principal, caller);
262
252
  }
263
253
  return caller;
@@ -282,22 +272,22 @@ function buildCoreCapService(appRouter, census = (0, http_request_census_singlet
282
272
  invoke: async (input, origin) => {
283
273
  countMeshCall(census, path, origin);
284
274
  const remoteNode = remoteOrigin(origin, options.ownNodeId);
285
- if (remoteNode !== null && exports.REMOTE_DENIED_NAMESPACES.has(namespace)) {
286
- throw new moleculer_1.Errors.MoleculerClientError(`"${path}" is not callable from another node (caller "${remoteNode}")`, 403, exports.CORE_CAP_REMOTE_FORBIDDEN_TYPE);
275
+ if (remoteNode !== null && REMOTE_DENIED_NAMESPACES.has(namespace)) {
276
+ throw new Errors.MoleculerClientError(`"${path}" is not callable from another node (caller "${remoteNode}")`, 403, CORE_CAP_REMOTE_FORBIDDEN_TYPE);
287
277
  }
288
278
  if (remoteNode !== null) {
289
- if (exports.REMOTE_PRIVILEGE_LOG_ONLY) {
279
+ if (REMOTE_PRIVILEGE_LOG_ONLY) {
290
280
  observeRemotePrivilege(remoteNode, path);
291
281
  }
292
- else if (path === exports.REMOTE_UPDATE_PACKAGE_PATH && options.remoteUpdateGrant) {
293
- const decision = await (0, remote_addon_update_grant_js_1.authorizeRemoteUpdatePackage)(remoteNode, input, options.remoteUpdateGrant);
282
+ else if (path === REMOTE_UPDATE_PACKAGE_PATH && options.remoteUpdateGrant) {
283
+ const decision = await authorizeRemoteUpdatePackage(remoteNode, input, options.remoteUpdateGrant);
294
284
  if (!decision.allowed) {
295
- throw new moleculer_1.Errors.MoleculerClientError(`"${path}" refused for caller "${remoteNode}": ${decision.reason ?? 'not permitted'}`, 403, exports.CORE_CAP_REMOTE_FORBIDDEN_TYPE);
285
+ throw new Errors.MoleculerClientError(`"${path}" refused for caller "${remoteNode}": ${decision.reason ?? 'not permitted'}`, 403, CORE_CAP_REMOTE_FORBIDDEN_TYPE);
296
286
  }
297
287
  }
298
- else if (!exports.REMOTE_PRIVILEGE_ALLOWLIST.has(path)) {
288
+ else if (!REMOTE_PRIVILEGE_ALLOWLIST.has(path)) {
299
289
  observeRemotePrivilegeRefused(remoteNode, path);
300
- throw new moleculer_1.Errors.MoleculerClientError(`"${path}" is not on the remote privilege grant (caller "${remoteNode}")`, 403, exports.CORE_CAP_REMOTE_FORBIDDEN_TYPE);
290
+ throw new Errors.MoleculerClientError(`"${path}" is not on the remote privilege grant (caller "${remoteNode}")`, 403, CORE_CAP_REMOTE_FORBIDDEN_TYPE);
301
291
  }
302
292
  }
303
293
  const invoke = resolveInvoker(callerFor(remoteNode === null ? 'mesh' : `node:${remoteNode}`), path);
@@ -307,7 +297,7 @@ function buildCoreCapService(appRouter, census = (0, http_request_census_singlet
307
297
  },
308
298
  });
309
299
  }
310
- return (0, system_1.createCoreCapService)({ actions });
300
+ return createCoreCapService({ actions });
311
301
  }
312
302
  /** The calling node when it is not the hub itself; `null` for the hub's own calls. */
313
303
  function remoteOrigin(origin, ownNodeId) {
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * The per-device COLLECTION dispatcher — a capability whose providers are
4
3
  * SOURCES of one device, listed beside each other.
@@ -60,12 +59,9 @@
60
59
  * camera with one provider behaves exactly as it did before this mount
61
60
  * existed, and it is pinned by spec.
62
61
  */
63
- Object.defineProperty(exports, "__esModule", { value: true });
64
- exports.SOURCE_LISTING_METHOD = void 0;
65
- exports.requireDeviceCollection = requireDeviceCollection;
66
- const system_1 = require("@camstack/system");
67
- const types_1 = require("@camstack/types");
68
- const server_1 = require("@trpc/server");
62
+ import { CAP_METHOD_NOT_IMPLEMENTED } from '@camstack/system';
63
+ import { deviceExtensionCapability, EXTENSION_SLOT_LISTING_METHOD, expandCapMethods, isArrayOutputSchema, reservedSourceOwner, unreachableExtensionSlotRow, } from '@camstack/types';
64
+ import { TRPCError } from '@trpc/server';
69
65
  /**
70
66
  * The device-collection CONVENTION: a cap whose providers are sources declares
71
67
  * this method, taking `{ deviceId }` and returning one row per source with a
@@ -73,7 +69,7 @@ const server_1 = require("@trpc/server");
73
69
  * without a second registry of id prefixes — the provider that mints the ids
74
70
  * is the one that names them.
75
71
  */
76
- exports.SOURCE_LISTING_METHOD = 'listSources';
72
+ export const SOURCE_LISTING_METHOD = 'listSources';
77
73
  /** The field on a source row that carries its id / clip-id namespace. */
78
74
  const SOURCE_ID_FIELD = 'source';
79
75
  /** The field on a source row that names the addon serving it (D555/D557). */
@@ -219,10 +215,10 @@ function isFanOutMethod(registry, capName, method) {
219
215
  const def = registry.getDefinition(capName);
220
216
  if (def === undefined)
221
217
  return false;
222
- const schema = (0, types_1.expandCapMethods)(def)[method];
218
+ const schema = expandCapMethods(def)[method];
223
219
  if (schema === undefined || schema.kind === 'subscription')
224
220
  return false;
225
- return (0, types_1.isArrayOutputSchema)(schema.output);
221
+ return isArrayOutputSchema(schema.output);
226
222
  }
227
223
  function errMessage(err) {
228
224
  return err instanceof Error ? err.message : String(err);
@@ -231,7 +227,7 @@ function errMessage(err) {
231
227
  async function callSource(source, method, input, capName, deviceId) {
232
228
  const fn = source.provider[method];
233
229
  if (typeof fn !== 'function') {
234
- throw new server_1.TRPCError({
230
+ throw new TRPCError({
235
231
  code: 'NOT_IMPLEMENTED',
236
232
  message: notImplementedMessage(capName, source.addonId, deviceId, method),
237
233
  });
@@ -246,8 +242,8 @@ async function callSource(source, method, input, capName, deviceId) {
246
242
  return await fn.call(source.provider, input);
247
243
  }
248
244
  catch (err) {
249
- if (errMessage(err).includes(system_1.CAP_METHOD_NOT_IMPLEMENTED)) {
250
- throw new server_1.TRPCError({
245
+ if (errMessage(err).includes(CAP_METHOD_NOT_IMPLEMENTED)) {
246
+ throw new TRPCError({
251
247
  code: 'NOT_IMPLEMENTED',
252
248
  message: notImplementedMessage(capName, source.addonId, deviceId, method),
253
249
  });
@@ -332,18 +328,18 @@ function unreachableSourceRow(addonId, reason) {
332
328
  * behaviour, D554 decision 6).
333
329
  */
334
330
  const CAP_FAILURE_ROWS = {
335
- [types_1.deviceExtensionCapability.name]: {
336
- [types_1.EXTENSION_SLOT_LISTING_METHOD]: types_1.unreachableExtensionSlotRow,
331
+ [deviceExtensionCapability.name]: {
332
+ [EXTENSION_SLOT_LISTING_METHOD]: unreachableExtensionSlotRow,
337
333
  },
338
334
  };
339
335
  function failureRowFor(capName, method) {
340
336
  const own = CAP_FAILURE_ROWS[capName]?.[method];
341
337
  if (own !== undefined)
342
338
  return own;
343
- return method === exports.SOURCE_LISTING_METHOD ? unreachableSourceRow : null;
339
+ return method === SOURCE_LISTING_METHOD ? unreachableSourceRow : null;
344
340
  }
345
341
  async function fanOut(sources, method, input, capName, deviceId, logger) {
346
- const isSourceListing = method === exports.SOURCE_LISTING_METHOD;
342
+ const isSourceListing = method === SOURCE_LISTING_METHOD;
347
343
  const failureRow = failureRowFor(capName, method);
348
344
  const settled = await Promise.allSettled(sources.map(async (source) => await callSource(source, method, input, capName, deviceId)));
349
345
  const rows = [];
@@ -403,7 +399,7 @@ function finishRows(source, rows, isSourceListing, capName, deviceId, logger) {
403
399
  }
404
400
  const id = Reflect.get(row, SOURCE_ID_FIELD);
405
401
  if (typeof id === 'string') {
406
- const owner = (0, types_1.reservedSourceOwner)(capName, id);
402
+ const owner = reservedSourceOwner(capName, id);
407
403
  if (owner !== null && owner !== source.addonId) {
408
404
  // A RESERVED id (D625) is the DEFAULT of a picker, expressed as a
409
405
  // value rather than as a sort order. A second row spelling it would
@@ -413,7 +409,7 @@ function finishRows(source, rows, isSourceListing, capName, deviceId, logger) {
413
409
  // and emptying a camera's picker over one bad row is worse than the
414
410
  // bad row. The guard in `scripts/` refuses the same spelling at build
415
411
  // time; this is what happens when an old build reaches a new hub.
416
- logger?.warn(`${capName}.${exports.SOURCE_LISTING_METHOD}: source id "${id}" is RESERVED for "${owner}" — this addon's row is dropped`, {
412
+ logger?.warn(`${capName}.${SOURCE_LISTING_METHOD}: source id "${id}" is RESERVED for "${owner}" — this addon's row is dropped`, {
417
413
  tags: { deviceId, addonId: source.addonId },
418
414
  meta: { capability: capName, sourceId: id, reservedFor: owner },
419
415
  });
@@ -427,7 +423,7 @@ function finishRows(source, rows, isSourceListing, capName, deviceId, logger) {
427
423
  async function claimsOf(sources, capName, deviceId, logger) {
428
424
  const claimed = new Map();
429
425
  const unknownClaims = [];
430
- const settled = await Promise.allSettled(sources.map(async (source) => await callSource(source, exports.SOURCE_LISTING_METHOD, { deviceId }, capName, deviceId)));
426
+ const settled = await Promise.allSettled(sources.map(async (source) => await callSource(source, SOURCE_LISTING_METHOD, { deviceId }, capName, deviceId)));
431
427
  for (const [index, result] of settled.entries()) {
432
428
  const source = sources[index];
433
429
  if (source === undefined)
@@ -435,7 +431,7 @@ async function claimsOf(sources, capName, deviceId, logger) {
435
431
  if (result.status === 'rejected' || !Array.isArray(result.value)) {
436
432
  // It could not name its sources, so it cannot be excluded on that basis
437
433
  // either — a read that FAILS must not destroy work (D49).
438
- logger?.warn(`${capName}.${exports.SOURCE_LISTING_METHOD}: source could not name its ids — routing falls back to it only if it is the only such source`, {
434
+ logger?.warn(`${capName}.${SOURCE_LISTING_METHOD}: source could not name its ids — routing falls back to it only if it is the only such source`, {
439
435
  tags: { deviceId, addonId: source.addonId },
440
436
  meta: {
441
437
  capability: capName,
@@ -501,7 +497,7 @@ async function dispatchScalar(sources, method, input, capName, deviceId, logger)
501
497
  tags: { deviceId },
502
498
  meta: { capability: capName, method, knownSources: known, input },
503
499
  });
504
- throw new server_1.TRPCError({
500
+ throw new TRPCError({
505
501
  code: 'BAD_REQUEST',
506
502
  message: `Capability "${capName}.${method}": no source of device ${deviceId} claims ` +
507
503
  `${JSON.stringify(input)}. Sources: ${known.length > 0 ? known.join(', ') : '(none named)'}. ` +
@@ -526,7 +522,7 @@ function pinnedProvider(sources, input, capName, deviceId) {
526
522
  const picked = sources.filter((source) => source.addonId === pin);
527
523
  if (picked.length > 0)
528
524
  return picked;
529
- throw new server_1.TRPCError({
525
+ throw new TRPCError({
530
526
  code: 'BAD_REQUEST',
531
527
  message: `Capability "${capName}": device ${deviceId} is not bound to provider "${pin}". ` +
532
528
  `Bound providers: ${sources.map((source) => source.addonId).join(', ') || '(none)'}. ` +
@@ -541,7 +537,7 @@ function pinnedProvider(sources, input, capName, deviceId) {
541
537
  * Returns null without a registry (the router then surfaces
542
538
  * PRECONDITION_FAILED), exactly as the singleton dispatcher does.
543
539
  */
544
- function requireDeviceCollection(registry, capName, logger) {
540
+ export function requireDeviceCollection(registry, capName, logger) {
545
541
  if (!registry)
546
542
  return null;
547
543
  const dispatcher = new Proxy({}, {
@@ -551,7 +547,7 @@ function requireDeviceCollection(registry, capName, logger) {
551
547
  return async (input) => {
552
548
  const deviceId = input !== null && typeof input === 'object' ? Reflect.get(input, 'deviceId') : undefined;
553
549
  if (typeof deviceId !== 'number') {
554
- throw new server_1.TRPCError({
550
+ throw new TRPCError({
555
551
  code: 'BAD_REQUEST',
556
552
  message: `${capName}.${prop}: input must carry numeric "deviceId"`,
557
553
  });
@@ -559,7 +555,7 @@ function requireDeviceCollection(registry, capName, logger) {
559
555
  const bound = await sourcesForDevice(registry, capName, deviceId, logger);
560
556
  const sources = pinnedProvider(bound, input, capName, deviceId);
561
557
  if (sources.length === 0) {
562
- throw new server_1.TRPCError({
558
+ throw new TRPCError({
563
559
  code: 'PRECONDITION_FAILED',
564
560
  message: `Capability "${capName}" not registered for device ${deviceId}`,
565
561
  });
@@ -580,7 +576,7 @@ function requireDeviceCollection(registry, capName, logger) {
580
576
  const answered = await callSource(first, prop, input, capName, deviceId);
581
577
  if (!Array.isArray(answered))
582
578
  return answered;
583
- return finishRows(first, answered, prop === exports.SOURCE_LISTING_METHOD, capName, deviceId, logger);
579
+ return finishRows(first, answered, prop === SOURCE_LISTING_METHOD, capName, deviceId, logger);
584
580
  }
585
581
  return await fanOut(sources, prop, input, capName, deviceId, logger);
586
582
  }
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Device-config secret redaction for NON-ADMIN principals.
4
3
  *
@@ -39,26 +38,11 @@
39
38
  * Pure module — no tRPC machinery — so the spec exercises it directly (same
40
39
  * pattern as `scope-access.ts` and `share-view-access.ts`).
41
40
  */
42
- Object.defineProperty(exports, "__esModule", { value: true });
43
- exports.NON_ADMIN_CONFIG_REDACTED_METHODS = exports.REDACTED_SECRET = void 0;
44
- exports.isSecretConfigKey = isSecretConfigKey;
45
- exports.redactDeviceInfoSecrets = redactDeviceInfoSecrets;
46
- exports.redactDeviceInfoRecordSecrets = redactDeviceInfoRecordSecrets;
47
- exports.redactSettingsSections = redactSettingsSections;
48
- exports.redactSettingsAggregate = redactSettingsAggregate;
49
- exports.redactSettingsForm = redactSettingsForm;
50
- exports.redactExportSetup = redactExportSetup;
51
- exports.redactDeepSecrets = redactDeepSecrets;
52
- exports.redactStatusAggregateSetup = redactStatusAggregateSetup;
53
- exports.redactStatusAggregateBatchSetup = redactStatusAggregateBatchSetup;
54
- exports.redactConfigEntries = redactConfigEntries;
55
- exports.redactStreamUrlSecrets = redactStreamUrlSecrets;
56
- exports.maskUrlCredentialsDeep = maskUrlCredentialsDeep;
57
41
  /** What a non-admin sees instead of the value. Matches the `***` convention
58
42
  * `maskUrlCredentials` already uses for credentials in log output, so one
59
43
  * redaction marker means one thing across the system. */
60
- const types_1 = require("@camstack/types");
61
- exports.REDACTED_SECRET = '***';
44
+ import { maskUrlCredentials } from '@camstack/types';
45
+ export const REDACTED_SECRET = '***';
62
46
  /**
63
47
  * Config keys whose VALUE is a credential.
64
48
  *
@@ -79,7 +63,7 @@ const SECRET_KEY_SUBSTRINGS = [
79
63
  'api_key',
80
64
  ];
81
65
  /** True when a config key names a credential. Case-insensitive substring match. */
82
- function isSecretConfigKey(key) {
66
+ export function isSecretConfigKey(key) {
83
67
  const lower = key.toLowerCase();
84
68
  return SECRET_KEY_SUBSTRINGS.some((needle) => lower.includes(needle));
85
69
  }
@@ -103,7 +87,7 @@ function declaredPathsOf(row) {
103
87
  /** Withhold every non-empty string at or below `value` (a declared secret node). */
104
88
  function withholdAll(value) {
105
89
  if (typeof value === 'string')
106
- return value.length > 0 ? exports.REDACTED_SECRET : value;
90
+ return value.length > 0 ? REDACTED_SECRET : value;
107
91
  if (Array.isArray(value))
108
92
  return value.map(withholdAll);
109
93
  if (!isRecord(value))
@@ -140,7 +124,7 @@ function withholdPath(value, segments) {
140
124
  */
141
125
  function backstop(value) {
142
126
  if (typeof value === 'string') {
143
- return value.includes('://') ? (0, types_1.maskUrlCredentials)(value) : value;
127
+ return value.includes('://') ? maskUrlCredentials(value) : value;
144
128
  }
145
129
  if (Array.isArray(value))
146
130
  return value.map(backstop);
@@ -150,7 +134,7 @@ function backstop(value) {
150
134
  for (const [key, child] of Object.entries(value)) {
151
135
  out[key] =
152
136
  isSecretConfigKey(key) && typeof child === 'string' && child.length > 0
153
- ? exports.REDACTED_SECRET
137
+ ? REDACTED_SECRET
154
138
  : backstop(child);
155
139
  }
156
140
  return out;
@@ -174,7 +158,7 @@ function redactConfigBlob(config, declared) {
174
158
  * Anything that is not a device row passes through untouched — a route that
175
159
  * errored upstream must not be rewritten into a plausible-looking shape.
176
160
  */
177
- function redactDeviceInfoSecrets(data) {
161
+ export function redactDeviceInfoSecrets(data) {
178
162
  if (Array.isArray(data))
179
163
  return data.map((row) => redactDeviceInfoSecrets(row));
180
164
  if (!isRecord(data))
@@ -193,7 +177,7 @@ function redactDeviceInfoSecrets(data) {
193
177
  * its own, so the function returns early having redacted nothing. A batch of a
194
178
  * single-device read must never be the ungated way to ask the same question.
195
179
  */
196
- function redactDeviceInfoRecordSecrets(data) {
180
+ export function redactDeviceInfoRecordSecrets(data) {
197
181
  if (!isRecord(data))
198
182
  return data;
199
183
  const out = {};
@@ -205,7 +189,7 @@ function redactDeviceInfoRecordSecrets(data) {
205
189
  * Project a `SettingsSchemaWithValues` (`{ sections: [{ fields: [...] }] }`).
206
190
  * Used by `getDeviceSettingsAggregate` and `getSettingsSchema`.
207
191
  */
208
- function redactSettingsSections(data) {
192
+ export function redactSettingsSections(data) {
209
193
  if (!isRecord(data))
210
194
  return data;
211
195
  const sections = data['sections'];
@@ -230,7 +214,7 @@ function redactSettingsSections(data) {
230
214
  * Project the combined aggregate, whose settings live one level down under
231
215
  * `settings`. The live half carries no config blob.
232
216
  */
233
- function redactSettingsAggregate(data) {
217
+ export function redactSettingsAggregate(data) {
234
218
  if (!isRecord(data))
235
219
  return data;
236
220
  const settings = data['settings'];
@@ -275,8 +259,8 @@ function redactFormValue(value, secret, itemFields) {
275
259
  if (value.length === 0)
276
260
  return value;
277
261
  if (secret)
278
- return exports.REDACTED_SECRET;
279
- return value.includes('://') ? (0, types_1.maskUrlCredentials)(value) : value;
262
+ return REDACTED_SECRET;
263
+ return value.includes('://') ? maskUrlCredentials(value) : value;
280
264
  }
281
265
  if (Array.isArray(value))
282
266
  return value.map((el) => redactFormValue(el, secret, itemFields));
@@ -318,7 +302,7 @@ function redactFormField(field) {
318
302
  // The HomeKit QR caption spells the setup code out in prose.
319
303
  const caption = field['caption'];
320
304
  return field['type'] === 'qr-code' && typeof caption === 'string' && caption.length > 0
321
- ? { ...redacted, caption: exports.REDACTED_SECRET }
305
+ ? { ...redacted, caption: REDACTED_SECRET }
322
306
  : redacted;
323
307
  }
324
308
  /**
@@ -335,7 +319,7 @@ function redactFormField(field) {
335
319
  * and `updateGlobalSettings` / `updateDeviceSettings` are admin-only, so a
336
320
  * redacted value can never be written back (D634).
337
321
  */
338
- function redactSettingsForm(data) {
322
+ export function redactSettingsForm(data) {
339
323
  if (!isRecord(data))
340
324
  return data;
341
325
  const sections = data['sections'];
@@ -360,7 +344,7 @@ function redactSettingsForm(data) {
360
344
  * panel renders it, so a non-admin keeps the link state and counts and never
361
345
  * receives the block (D634 r2). One object or a fanned-out array.
362
346
  */
363
- function redactExportSetup(data) {
347
+ export function redactExportSetup(data) {
364
348
  if (Array.isArray(data))
365
349
  return data.map((row) => redactExportSetup(row));
366
350
  if (!isRecord(data) || !('setup' in data))
@@ -375,7 +359,7 @@ function redactExportSetup(data) {
375
359
  * `access_token` and `?token=` picture URLs), an integration's `info`, a
376
360
  * broker list's `url` (D634 r3).
377
361
  */
378
- function redactDeepSecrets(data) {
362
+ export function redactDeepSecrets(data) {
379
363
  return redactFormValue(data, false, undefined);
380
364
  }
381
365
  /** The status-aggregate entry that carries export pairing material. */
@@ -385,13 +369,13 @@ const DEVICE_EXPORT_CAP = 'device-export';
385
369
  * `device-export` entry loses its `setup` (D634 r3 — defence in depth; the
386
370
  * aggregation itself no longer asks a system collection cap per device).
387
371
  */
388
- function redactStatusAggregateSetup(data) {
372
+ export function redactStatusAggregateSetup(data) {
389
373
  if (!isRecord(data) || !(DEVICE_EXPORT_CAP in data))
390
374
  return data;
391
375
  return { ...data, [DEVICE_EXPORT_CAP]: redactExportSetup(data[DEVICE_EXPORT_CAP]) };
392
376
  }
393
377
  /** Project a batch status aggregate (`Record<deviceId, Record<capName, status>>`). */
394
- function redactStatusAggregateBatchSetup(data) {
378
+ export function redactStatusAggregateBatchSetup(data) {
395
379
  if (!isRecord(data))
396
380
  return data;
397
381
  const out = {};
@@ -401,7 +385,7 @@ function redactStatusAggregateBatchSetup(data) {
401
385
  return out;
402
386
  }
403
387
  /** Project a flat `ConfigEntry[]` — `getConfigSchema`'s `{ key, value }` rows. */
404
- function redactConfigEntries(data) {
388
+ export function redactConfigEntries(data) {
405
389
  if (!Array.isArray(data))
406
390
  return data;
407
391
  return data.map(redactFormField);
@@ -428,7 +412,7 @@ const URL_FIELD_KEYS = ['url', 'mutedUrl'];
428
412
  * (`codec`, `label`) and a non-string value pass through. Non-row payloads
429
413
  * pass through untouched — an upstream error must not be rewritten.
430
414
  */
431
- function redactStreamUrlSecrets(data) {
415
+ export function redactStreamUrlSecrets(data) {
432
416
  if (Array.isArray(data))
433
417
  return data.map((row) => redactStreamUrlSecrets(row));
434
418
  if (!isRecord(data))
@@ -437,7 +421,7 @@ function redactStreamUrlSecrets(data) {
437
421
  for (const [key, value] of Object.entries(data)) {
438
422
  out[key] =
439
423
  URL_FIELD_KEYS.includes(key) && typeof value === 'string' && value.length > 0
440
- ? (0, types_1.maskUrlCredentials)(value)
424
+ ? maskUrlCredentials(value)
441
425
  : value;
442
426
  }
443
427
  return out;
@@ -451,9 +435,9 @@ function redactStreamUrlSecrets(data) {
451
435
  * any non-admin (D783). Only strings holding `://` are touched; no key is
452
436
  * judged by its name here, so `eventTypeTokens` & co. keep their values.
453
437
  */
454
- function maskUrlCredentialsDeep(data) {
438
+ export function maskUrlCredentialsDeep(data) {
455
439
  if (typeof data === 'string')
456
- return data.includes('://') ? (0, types_1.maskUrlCredentials)(data) : data;
440
+ return data.includes('://') ? maskUrlCredentials(data) : data;
457
441
  if (Array.isArray(data))
458
442
  return data.map(maskUrlCredentialsDeep);
459
443
  if (!isRecord(data))
@@ -480,7 +464,7 @@ function maskUrlCredentialsDeep(data) {
480
464
  * `device-config-secret-redaction.spec.ts` pins the list so the addition is a
481
465
  * failing test rather than a silent leak.
482
466
  */
483
- exports.NON_ADMIN_CONFIG_REDACTED_METHODS = new Map([
467
+ export const NON_ADMIN_CONFIG_REDACTED_METHODS = new Map([
484
468
  // ── Addon settings forms (D634) — hydrated with the STORED secret ──
485
469
  ['addonSettings.getGlobalSettings', redactSettingsForm],
486
470
  ['addonSettings.getIntegrationSettings', redactSettingsForm],