@camstack/system 1.2.22 → 1.2.24

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 (62) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +0 -9
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -40
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -40
  12. package/dist/builtins/console-logging/index.js +1 -1
  13. package/dist/builtins/console-logging/index.mjs +1 -1
  14. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  18. package/dist/builtins/hub-forwarder/index.js +1 -1
  19. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  20. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  21. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  22. package/dist/builtins/local-network/local-network.addon.d.ts +16 -0
  23. package/dist/builtins/local-network/local-network.addon.js +30 -2
  24. package/dist/builtins/local-network/local-network.addon.mjs +30 -2
  25. package/dist/builtins/loki-logging/index.js +34 -12
  26. package/dist/builtins/loki-logging/index.mjs +34 -12
  27. package/dist/builtins/loki-logging/loki-logging.addon.d.ts +19 -0
  28. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  30. package/dist/builtins/platform-probe/index.js +1 -1
  31. package/dist/builtins/platform-probe/index.mjs +1 -1
  32. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  34. package/dist/builtins/snapshot/index.js +1 -1
  35. package/dist/builtins/snapshot/index.mjs +1 -1
  36. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  38. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  40. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +7 -0
  41. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +108 -4
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +108 -4
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +11 -1
  44. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +5 -0
  45. package/dist/builtins/system-config/system-config.addon.js +1 -1
  46. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  47. package/dist/builtins/winston-logging/index.js +1 -1
  48. package/dist/builtins/winston-logging/index.mjs +1 -1
  49. package/dist/{dist-C9_XdXl5.mjs → dist-CIek6F9X.mjs} +436 -72
  50. package/dist/{dist-j49ewCPY.js → dist-CS0pdC8l.js} +436 -72
  51. package/dist/index.js +58 -8
  52. package/dist/index.mjs +58 -8
  53. package/dist/kernel/capability-registry.d.ts +9 -0
  54. package/dist/kernel/transport/local-child-registry.d.ts +38 -0
  55. package/dist/kernel/transport/local-transport.d.ts +11 -1
  56. package/dist/kernel/transport/parent-unowned-call.d.ts +22 -0
  57. package/dist/kernel/transport/socket-channel.d.ts +28 -1
  58. package/dist/logging/log-manager.d.ts +32 -1
  59. package/dist/logging/partitioned-log-buffer.d.ts +15 -3
  60. package/dist/{manifest-python-deps-CnRW2Utv.js → manifest-python-deps-BbOZZbVt.js} +56 -12
  61. package/dist/{manifest-python-deps-B30qVAuW.mjs → manifest-python-deps-C9qhvMUi.mjs} +57 -13
  62. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-j49ewCPY.js");
3
+ const require_dist = require("./dist-CS0pdC8l.js");
4
4
  const require_model_download_service = require("./model-download-service-hf0ookyy.js");
5
- const require_manifest_python_deps = require("./manifest-python-deps-CnRW2Utv.js");
5
+ const require_manifest_python_deps = require("./manifest-python-deps-BbOZZbVt.js");
6
6
  const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
7
7
  const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
8
8
  const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
@@ -991,6 +991,18 @@ var PartitionedLogBuffer = class {
991
991
  this.maxTotalEntries = options.maxTotalEntries ?? null;
992
992
  this.pruneLevel = options.pruneLevel ?? "debug";
993
993
  }
994
+ /**
995
+ * Apply new limits at runtime. Shrinking takes effect as entries are pushed
996
+ * (each partition trims to the new capacity on its next write) — existing
997
+ * entries are NOT dropped eagerly: losing history the operator is currently
998
+ * reading, the instant they lower a number, is a worse surprise than a
999
+ * momentarily oversized buffer.
1000
+ */
1001
+ reconfigure(options) {
1002
+ if (options.perAddonCapacity !== void 0 && options.perAddonCapacity > 0) this.perAddonCapacity = options.perAddonCapacity;
1003
+ if (options.maxTotalEntries !== void 0) this.maxTotalEntries = options.maxTotalEntries;
1004
+ if (options.pruneLevel !== void 0) this.pruneLevel = options.pruneLevel;
1005
+ }
994
1006
  bufferFor(key) {
995
1007
  let buf = this.buffers.get(key);
996
1008
  if (buf === void 0) {
@@ -1130,11 +1142,24 @@ var ScopedLogger = class ScopedLogger {
1130
1142
  };
1131
1143
  }
1132
1144
  };
1133
- //#endregion
1134
- //#region src/logging/log-manager.ts
1135
1145
  var LogManager = class {
1136
1146
  ringBuffer;
1147
+ /**
1148
+ * Destinations, each tagged with the addon that provides it (when known) so
1149
+ * the fan-out can honour the operator's per-destination toggle.
1150
+ */
1137
1151
  destinations = [];
1152
+ /**
1153
+ * "Is this destination enabled?", injected by the wiring side (which owns
1154
+ * the capability registry). Absent ⇒ everything is enabled.
1155
+ *
1156
+ * WHY: the orchestrator's Enable/Disable toggle only added the addon to
1157
+ * `disabledProviders` and NOTHING consulted it for `log-destination` — so
1158
+ * console and winston could not be turned off at all and the badge in the UI
1159
+ * lied, while Loki appeared to work only because it carried a SECOND,
1160
+ * private `enabled` setting of its own (audit 2026-07-30).
1161
+ */
1162
+ isDestinationEnabled;
1138
1163
  subscribers = /* @__PURE__ */ new Map();
1139
1164
  deviceNameLookup = null;
1140
1165
  /**
@@ -1169,8 +1194,11 @@ var LogManager = class {
1169
1194
  createLogger(scope) {
1170
1195
  return new ScopedLogger(scope, (entry) => {
1171
1196
  const enriched = this.enrichDeviceName(entry);
1172
- this.ringBuffer.push(enriched);
1173
- for (const dest of this.destinations) dest.write(enriched);
1197
+ if (this.isDestinationEnabled?.("log-buffer") !== false) this.ringBuffer.push(enriched);
1198
+ for (const entry of this.destinations) {
1199
+ if (entry.addonId !== void 0 && this.isDestinationEnabled?.(entry.addonId) === false) continue;
1200
+ entry.dest.write(enriched);
1201
+ }
1174
1202
  for (const [, sub] of this.subscribers) if (this.matchesFilter(enriched, sub.filter)) try {
1175
1203
  sub.callback(enriched);
1176
1204
  } catch {}
@@ -1228,15 +1256,26 @@ var LogManager = class {
1228
1256
  * traffic starts. Lets a destination added mid-boot
1229
1257
  * still receive boot-time log entries.
1230
1258
  */
1259
+ /** Apply new in-memory buffer limits at runtime (see PartitionedLogBuffer). */
1260
+ reconfigureBuffer(options) {
1261
+ this.ringBuffer.reconfigure(options);
1262
+ }
1263
+ /** Set the per-destination enablement check (see {@link isDestinationEnabled}). */
1264
+ setDestinationEnabledCheck(check) {
1265
+ this.isDestinationEnabled = check ?? void 0;
1266
+ }
1231
1267
  addDestination(dest, opts = {}) {
1232
1268
  const replay = opts.replay ?? true;
1233
- this.destinations.push(dest);
1269
+ this.destinations.push(opts.addonId === void 0 ? { dest } : {
1270
+ dest,
1271
+ addonId: opts.addonId
1272
+ });
1234
1273
  if (replay) for (const entry of this.ringBuffer.query({})) try {
1235
1274
  dest.write(entry);
1236
1275
  } catch {}
1237
1276
  }
1238
1277
  removeDestination(dest) {
1239
- const index = this.destinations.indexOf(dest);
1278
+ const index = this.destinations.findIndex((d) => d.dest === dest);
1240
1279
  if (index !== -1) this.destinations.splice(index, 1);
1241
1280
  }
1242
1281
  query(filter) {
@@ -5168,6 +5207,17 @@ var CapabilityRegistry = class CapabilityRegistry {
5168
5207
  if (!state || state.definition.mode !== "collection") return [];
5169
5208
  return [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId));
5170
5209
  }
5210
+ /**
5211
+ * Is `addonId` currently DISABLED as a provider of `capability`?
5212
+ *
5213
+ * Exposed because the disabled set was write-only for `log-destination`:
5214
+ * the orchestrator toggle added the addon here and nothing ever read it, so
5215
+ * console and winston could not be turned off at all while the UI badge said
5216
+ * they were (audit 2026-07-30).
5217
+ */
5218
+ isProviderDisabled(capability, addonId) {
5219
+ return this.capabilities.get(capability)?.disabledProviders.has(addonId) === true;
5220
+ }
5171
5221
  /** Get the full CapabilityDefinition for a declared capability. */
5172
5222
  getDefinition(capability) {
5173
5223
  return this.capabilities.get(capability)?.definition;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { B as logLevelAtMost, Dt as readinessKey, Et as parseJsonUnknown$1, F as isVoidInput, I as kebabToCamel, L as lifecycleJobSchema, M as isArrayOutputSchema, N as isCollectionArrayMethod, Ot as resolveCapMount, P as isObjectInput, Tt as parseJsonObject, V as looseSchema, W as objectInputDeclaresAddonId, _t as asString$1, c as RUNTIME_DEFAULTS, ct as DEVICE_STATUS_METHOD, ft as ReadinessRegistry, gt as asNumber, ht as asJsonObject$1, it as errMsg$1, jt as EventCategory$1, k as extractNestedAddonId, kt as scopeKey, m as addonSettingsCapability, ot as DATAPLANE_SECRET_HEADER$1, pt as ReadinessTimeoutError, q as procedureAuthKey, s as METHOD_ACCESS_MAP, st as DEVICE_SETTINGS_CONTRIBUTION_METHODS, t as ALL_CAPABILITY_DEFINITIONS, vt as createEvent, xt as expandCapMethods, yt as emitDownForOwnedCaps } from "./dist-C9_XdXl5.mjs";
2
+ import { B as logLevelAtMost, Dt as readinessKey, Et as parseJsonUnknown$1, F as isVoidInput, I as kebabToCamel, L as lifecycleJobSchema, M as isArrayOutputSchema, N as isCollectionArrayMethod, Ot as resolveCapMount, P as isObjectInput, Tt as parseJsonObject, V as looseSchema, W as objectInputDeclaresAddonId, _t as asString$1, c as RUNTIME_DEFAULTS, ct as DEVICE_STATUS_METHOD, ft as ReadinessRegistry, gt as asNumber, ht as asJsonObject$1, it as errMsg$1, jt as EventCategory$1, k as extractNestedAddonId, kt as scopeKey, m as addonSettingsCapability, ot as DATAPLANE_SECRET_HEADER$1, pt as ReadinessTimeoutError, q as procedureAuthKey, s as METHOD_ACCESS_MAP, st as DEVICE_SETTINGS_CONTRIBUTION_METHODS, t as ALL_CAPABILITY_DEFINITIONS, vt as createEvent, xt as expandCapMethods, yt as emitDownForOwnedCaps } from "./dist-CIek6F9X.mjs";
3
3
  import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-Cp9f4dk6.mjs";
4
- import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as resolveAddonClass, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as runNpm, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveNpmInvocation, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-B30qVAuW.mjs";
4
+ import { $ as buildNativeCapProxy, A as createHubCapForwardService, B as AGENT_CAP_FWD_ACTION, C as brokerTransportLink, Ct as resolveAddonClass, D as localProviderLink, E as ipcParentLink, F as createUdsLogger, G as callWithServiceDiscovery, H as CapRouteResolver, I as createUdsLoggerWithControl, J as UdsLocalTransportServer, K as createLocalTransport, L as LocalChildClient, M as createUdsEventBridge, N as createUdsEventBus, O as HUB_CAP_FWD_ACTION, P as udsChildLogToWorkerEntry, Q as encodeFrame, R as LocalChildRegistry, S as brokerCallForCap, St as runNpm, T as ipcChildLink, U as CapRouteError, V as AGENT_CAP_FWD_SERVICE, W as classifyCapRoute, X as localEndpointPath, Y as SocketChannel, Z as FrameDecoder, _ as createKernelHwAccel, _t as CapabilityHandle, a as getWorkerDeviceRegistry, b as __resetCapUsageRegistryForTests, bt as installManifestNativeDeps, c as setHubConnected, ct as NATIVE_PROVIDER_SERVICE_INFIX, d as getBrokerEventBus, dt as capBareAction, et as buildUdsNativeCapProxy, f as getMoleculerEventStats, ft as capServiceName, g as AddonDepsManager, gt as DeviceRegistry, h as subscribePassthrough, ht as serializeTypedArrays, i as createUdsAddonContext, it as mountNativeCapService, j as createParentUnownedCallHandler, k as HUB_CAP_FWD_SERVICE, l as EVENT_TOPIC_PREFIX, lt as capActionName, m as setNodeEventInterest, mt as deserializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as createAddonService, p as registerEventBusService, pt as parseCapAction, q as UdsLocalTransportClient, r as createAddonContext, s as getOrInitReadinessRegistryForClient, st as validateProviderRegistrations, t as installManifestPythonDeps, tt as createBrokerDeviceManagerApi, u as clusterEventTopic, ut as capActionSuffix, v as resolveHwAccel, vt as CapabilityUnavailableError, w as buildLinkChain, wt as createAddonDataPlaneFacility, x as getCapUsageRegistry, xt as resolveNpmInvocation, y as CapUsageRegistry, yt as copyBundledNativeModules, z as UDS_NO_ROUTE_PREFIX } from "./manifest-python-deps-C9qhvMUi.mjs";
5
5
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-BkP504Vq.mjs";
6
6
  import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./builtins/sqlite-storage/filesystem-storage.addon.mjs";
7
7
  import { SqliteSettingsAddon, t as SqliteSettingsBackend } from "./builtins/sqlite-storage/sqlite-settings.addon.mjs";
@@ -984,6 +984,18 @@ var PartitionedLogBuffer = class {
984
984
  this.maxTotalEntries = options.maxTotalEntries ?? null;
985
985
  this.pruneLevel = options.pruneLevel ?? "debug";
986
986
  }
987
+ /**
988
+ * Apply new limits at runtime. Shrinking takes effect as entries are pushed
989
+ * (each partition trims to the new capacity on its next write) — existing
990
+ * entries are NOT dropped eagerly: losing history the operator is currently
991
+ * reading, the instant they lower a number, is a worse surprise than a
992
+ * momentarily oversized buffer.
993
+ */
994
+ reconfigure(options) {
995
+ if (options.perAddonCapacity !== void 0 && options.perAddonCapacity > 0) this.perAddonCapacity = options.perAddonCapacity;
996
+ if (options.maxTotalEntries !== void 0) this.maxTotalEntries = options.maxTotalEntries;
997
+ if (options.pruneLevel !== void 0) this.pruneLevel = options.pruneLevel;
998
+ }
987
999
  bufferFor(key) {
988
1000
  let buf = this.buffers.get(key);
989
1001
  if (buf === void 0) {
@@ -1123,11 +1135,24 @@ var ScopedLogger = class ScopedLogger {
1123
1135
  };
1124
1136
  }
1125
1137
  };
1126
- //#endregion
1127
- //#region src/logging/log-manager.ts
1128
1138
  var LogManager = class {
1129
1139
  ringBuffer;
1140
+ /**
1141
+ * Destinations, each tagged with the addon that provides it (when known) so
1142
+ * the fan-out can honour the operator's per-destination toggle.
1143
+ */
1130
1144
  destinations = [];
1145
+ /**
1146
+ * "Is this destination enabled?", injected by the wiring side (which owns
1147
+ * the capability registry). Absent ⇒ everything is enabled.
1148
+ *
1149
+ * WHY: the orchestrator's Enable/Disable toggle only added the addon to
1150
+ * `disabledProviders` and NOTHING consulted it for `log-destination` — so
1151
+ * console and winston could not be turned off at all and the badge in the UI
1152
+ * lied, while Loki appeared to work only because it carried a SECOND,
1153
+ * private `enabled` setting of its own (audit 2026-07-30).
1154
+ */
1155
+ isDestinationEnabled;
1131
1156
  subscribers = /* @__PURE__ */ new Map();
1132
1157
  deviceNameLookup = null;
1133
1158
  /**
@@ -1162,8 +1187,11 @@ var LogManager = class {
1162
1187
  createLogger(scope) {
1163
1188
  return new ScopedLogger(scope, (entry) => {
1164
1189
  const enriched = this.enrichDeviceName(entry);
1165
- this.ringBuffer.push(enriched);
1166
- for (const dest of this.destinations) dest.write(enriched);
1190
+ if (this.isDestinationEnabled?.("log-buffer") !== false) this.ringBuffer.push(enriched);
1191
+ for (const entry of this.destinations) {
1192
+ if (entry.addonId !== void 0 && this.isDestinationEnabled?.(entry.addonId) === false) continue;
1193
+ entry.dest.write(enriched);
1194
+ }
1167
1195
  for (const [, sub] of this.subscribers) if (this.matchesFilter(enriched, sub.filter)) try {
1168
1196
  sub.callback(enriched);
1169
1197
  } catch {}
@@ -1221,15 +1249,26 @@ var LogManager = class {
1221
1249
  * traffic starts. Lets a destination added mid-boot
1222
1250
  * still receive boot-time log entries.
1223
1251
  */
1252
+ /** Apply new in-memory buffer limits at runtime (see PartitionedLogBuffer). */
1253
+ reconfigureBuffer(options) {
1254
+ this.ringBuffer.reconfigure(options);
1255
+ }
1256
+ /** Set the per-destination enablement check (see {@link isDestinationEnabled}). */
1257
+ setDestinationEnabledCheck(check) {
1258
+ this.isDestinationEnabled = check ?? void 0;
1259
+ }
1224
1260
  addDestination(dest, opts = {}) {
1225
1261
  const replay = opts.replay ?? true;
1226
- this.destinations.push(dest);
1262
+ this.destinations.push(opts.addonId === void 0 ? { dest } : {
1263
+ dest,
1264
+ addonId: opts.addonId
1265
+ });
1227
1266
  if (replay) for (const entry of this.ringBuffer.query({})) try {
1228
1267
  dest.write(entry);
1229
1268
  } catch {}
1230
1269
  }
1231
1270
  removeDestination(dest) {
1232
- const index = this.destinations.indexOf(dest);
1271
+ const index = this.destinations.findIndex((d) => d.dest === dest);
1233
1272
  if (index !== -1) this.destinations.splice(index, 1);
1234
1273
  }
1235
1274
  query(filter) {
@@ -5161,6 +5200,17 @@ var CapabilityRegistry = class CapabilityRegistry {
5161
5200
  if (!state || state.definition.mode !== "collection") return [];
5162
5201
  return [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId));
5163
5202
  }
5203
+ /**
5204
+ * Is `addonId` currently DISABLED as a provider of `capability`?
5205
+ *
5206
+ * Exposed because the disabled set was write-only for `log-destination`:
5207
+ * the orchestrator toggle added the addon here and nothing ever read it, so
5208
+ * console and winston could not be turned off at all while the UI badge said
5209
+ * they were (audit 2026-07-30).
5210
+ */
5211
+ isProviderDisabled(capability, addonId) {
5212
+ return this.capabilities.get(capability)?.disabledProviders.has(addonId) === true;
5213
+ }
5164
5214
  /** Get the full CapabilityDefinition for a declared capability. */
5165
5215
  getDefinition(capability) {
5166
5216
  return this.capabilities.get(capability)?.definition;
@@ -311,6 +311,15 @@ export declare class CapabilityRegistry {
311
311
  */
312
312
  getCollectionEntries<K extends keyof CollectionCapabilityMap>(capability: K): readonly (readonly [string, CollectionCapabilityMap[K]])[];
313
313
  getCollectionEntries<T = unknown>(capability: string): readonly (readonly [string, T])[];
314
+ /**
315
+ * Is `addonId` currently DISABLED as a provider of `capability`?
316
+ *
317
+ * Exposed because the disabled set was write-only for `log-destination`:
318
+ * the orchestrator toggle added the addon here and nothing ever read it, so
319
+ * console and winston could not be turned off at all while the UI badge said
320
+ * they were (audit 2026-07-30).
321
+ */
322
+ isProviderDisabled(capability: string, addonId: string): boolean;
314
323
  /** Get the full CapabilityDefinition for a declared capability. */
315
324
  getDefinition(capability: string): CapabilityDefinition | undefined;
316
325
  /** Get the mode declared for a capability. */
@@ -79,6 +79,34 @@ export interface LocalChildRegistryOptions {
79
79
  * distinguish a pin-to-self from a pin-to-another-node.
80
80
  */
81
81
  readonly ownNodeId?: string;
82
+ /**
83
+ * Does `(capName, method)` name a `mode:'collection'` array method whose
84
+ * contract is the UNION across every provider? Such a call must NOT be
85
+ * short-circuited to a local sibling: `resolveChildId` picks ONE provider
86
+ * (first-registered, or the singleton preference — meaningless here), so the
87
+ * caller would see a fraction of the catalog the hub's own tRPC router
88
+ * returns. It goes to `onUnownedCall`, which owns the aggregate over local
89
+ * siblings, in-process providers and remote nodes alike.
90
+ *
91
+ * `notification-output` has three provider siblings; the Notification Center
92
+ * landed on one holding no targets, read the empty list as "target deleted"
93
+ * and permanently dead-lettered every notification it ever produced
94
+ * (2026-07-30). Omitted ⇒ prior behaviour exactly (sibling short-circuit for
95
+ * everything). The kernel has no cap registry, so the wiring side injects it.
96
+ */
97
+ readonly isAggregatedCollectionMethod?: (capName: string, method: string) => boolean;
98
+ /**
99
+ * Per-cap-method bound for UDS cap calls, in ms — read from the cap
100
+ * definition's declared `timeoutMs`. The SAME resolver the remote plane uses
101
+ * (`CapRouteResolver.capTimeoutMs`), so the two planes agree by construction
102
+ * instead of by coincidence.
103
+ *
104
+ * Without this the channel default (60 s) would apply to everything, and a
105
+ * legitimately long method — `applyServerUpdate` declares 16 min because it
106
+ * awaits a full npm install — would be cut off mid-run. Omitted ⇒ the
107
+ * channel default for every cap call.
108
+ */
109
+ readonly capTimeoutMs?: (capName: string, method: string) => number | undefined;
82
110
  }
83
111
  /**
84
112
  * Parent-side authority for local addon-runners reachable over a
@@ -100,6 +128,10 @@ export declare class LocalChildRegistry {
100
128
  private readonly resolveChildIdForAddon?;
101
129
  /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
102
130
  private readonly ownNodeId?;
131
+ /** See {@link LocalChildRegistryOptions.isAggregatedCollectionMethod}. */
132
+ private readonly isAggregatedCollectionMethod?;
133
+ /** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
134
+ private readonly capTimeoutMs?;
103
135
  /** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
104
136
  private readonly egressRoutedCaps;
105
137
  /** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
@@ -209,6 +241,12 @@ export declare class LocalChildRegistry {
209
241
  */
210
242
  isChildKnown(childId: string): boolean;
211
243
  childProvides(childId: string, capName: string, deviceId?: number): boolean;
244
+ /**
245
+ * Per-request options for a cap call: the cap method's declared `timeoutMs`
246
+ * when one exists, else `undefined` so the channel applies its default.
247
+ * Mirrors `CapRouteResolver.callTimeout` for the remote plane.
248
+ */
249
+ private capRequestOpts;
212
250
  /** Forward a cap method call to a SPECIFIC child by id over UDS; rejects if that child is absent. */
213
251
  callCapOnChild(childId: string, input: CapCallInput): Promise<unknown>;
214
252
  /** Forward a cap method call to the owning child over UDS; rejects if none. */
@@ -19,9 +19,19 @@ export type Frame = {
19
19
  };
20
20
  export type RequestHandler = (body: unknown) => Promise<unknown>;
21
21
  export type EventHandler = (body: unknown) => void;
22
+ /** Per-request options a {@link LocalChannel} implementation may honour. */
23
+ export interface LocalRequestOptions {
24
+ /**
25
+ * Bound on this request in ms; `0` or negative disables it. Omitted ⇒ the
26
+ * implementation's default. Cap calls pass the cap method's declared
27
+ * `timeoutMs` so a legitimately long method (`applyServerUpdate`, 16 min) is
28
+ * not cut short.
29
+ */
30
+ readonly timeoutMs?: number;
31
+ }
22
32
  /** A bidirectional request/response + one-way event channel over one socket. */
23
33
  export interface LocalChannel {
24
- request(body: unknown): Promise<unknown>;
34
+ request(body: unknown, opts?: LocalRequestOptions): Promise<unknown>;
25
35
  emit(body: unknown): void;
26
36
  onRequest(handler: RequestHandler): void;
27
37
  onEvent(handler: EventHandler): void;
@@ -110,6 +110,28 @@ export interface ParentUnownedCallDeps {
110
110
  * `CapabilityDefinition`s and the registry) injects this.
111
111
  */
112
112
  readonly resolveEmptyCollection?: (capName: string, method: string) => readonly unknown[] | null;
113
+ /**
114
+ * Optional collection FAN-OUT. Returns the union of `method` across every
115
+ * registered provider of a `mode:'collection'` cap, or `null` when the
116
+ * (cap, method) pair is not an aggregated collection array-method.
117
+ *
118
+ * Why: routing resolves ONE provider (`resolveChildId` picks the
119
+ * first-registered child, or the singleton preference — meaningless for a
120
+ * collection). The hub's tRPC cap-router instead fans array methods across
121
+ * every provider (`concatArrayMethod`). A forked addon calling the same cap
122
+ * through `ctx.api` therefore saw a DIFFERENT, smaller answer than the hub's
123
+ * own router — and for `notification-output`, whose three providers include
124
+ * two that hold no targets, it saw `[]`. The Notification Center read that
125
+ * empty catalog as "the target was deleted" and permanently dead-lettered
126
+ * every notification it ever produced (2026-07-30).
127
+ *
128
+ * Skipped when the call carries an explicit `nodeId` pin — a pin must route
129
+ * to its node, never be answered by a cluster-wide union. The kernel layer
130
+ * has no cap registry, so the wiring side injects this (same shape as
131
+ * {@link resolveEmptyCollection}, and it shares that path's aggregation code
132
+ * so the two answers cannot drift).
133
+ */
134
+ readonly callCollectionAggregate?: (capName: string, method: string, args: unknown) => Promise<readonly unknown[] | null>;
113
135
  /**
114
136
  * Optional predicate — returns `true` when `capName` is a HUB-CORE `$`-service
115
137
  * cap (`system`, `addons`, `nodes`, `capabilities`, `stream-probe`, …): served
@@ -1,5 +1,21 @@
1
1
  import { Socket } from 'node:net';
2
2
  import { LocalChannel, RequestHandler, EventHandler } from './local-transport.js';
3
+ /**
4
+ * Default bound on one UDS request, when the caller names none.
5
+ *
6
+ * Chosen to match `REMOTE_CALL_TIMEOUT_MS` in `cap-route-resolver.ts`: the SAME
7
+ * cap method already dies at 60 s when it resolves to a remote node, so
8
+ * applying the same bound locally makes the two planes consistent rather than
9
+ * newly restrictive. Callers with a legitimately longer method (the cap
10
+ * layer's declared `timeoutMs`, e.g. `applyServerUpdate` at 16 min) pass it
11
+ * explicitly.
12
+ */
13
+ export declare const DEFAULT_UDS_REQUEST_TIMEOUT_MS = 60000;
14
+ /** Per-request options for {@link SocketChannel.request}. */
15
+ export interface SocketRequestOptions {
16
+ /** Bound in ms; `0` or negative disables the timer entirely. */
17
+ readonly timeoutMs?: number;
18
+ }
3
19
  export declare class SocketChannel implements LocalChannel {
4
20
  private readonly socket;
5
21
  private nextId;
@@ -11,7 +27,18 @@ export declare class SocketChannel implements LocalChannel {
11
27
  private closed;
12
28
  private closeFired;
13
29
  constructor(socket: Socket);
14
- request(body: unknown): Promise<unknown>;
30
+ /**
31
+ * Send a request and wait for the peer's response.
32
+ *
33
+ * Bounded. Without a timer this settles on exactly two events — a matching
34
+ * `res` frame, or the socket's `close` (which drains `pending`) — so a peer
35
+ * that receives the request and then neither answers nor closes leaves the
36
+ * caller pending forever. That is a wedged handler, or a half-open socket
37
+ * after a child died without a clean teardown, and it is how camera 615 spent
38
+ * 30+ minutes with every inference permit held by a call that was never
39
+ * coming back.
40
+ */
41
+ request(body: unknown, opts?: SocketRequestOptions): Promise<unknown>;
15
42
  emit(body: unknown): void;
16
43
  /** Replace the request handler. Only one handler is active at a time. */
17
44
  onRequest(handler: RequestHandler): void;
@@ -1,4 +1,4 @@
1
- import { LogEntry, LogFilter } from './log-ring-buffer.js';
1
+ import { LogEntry, LogFilter, LogLevel } from './log-ring-buffer.js';
2
2
  import { PartitionedLogBufferOptions } from './partitioned-log-buffer.js';
3
3
  import { IScopedLogger } from './scoped-logger.js';
4
4
  export interface ILogDestination {
@@ -7,9 +7,31 @@ export interface ILogDestination {
7
7
  write(entry: LogEntry): void;
8
8
  query?(filter: LogFilter): Promise<readonly LogEntry[]>;
9
9
  }
10
+ /**
11
+ * The reserved destination id of the in-memory buffer. Not an addon: the
12
+ * buffer must exist before any addon loads (boot lines) and it backs
13
+ * `logs.query`/`subscribe`, so it lives in the kernel — but it answers to the
14
+ * SAME orchestrator toggle as every other destination.
15
+ */
16
+ export declare const LOG_BUFFER_DESTINATION_ID = "log-buffer";
10
17
  export declare class LogManager {
11
18
  private readonly ringBuffer;
19
+ /**
20
+ * Destinations, each tagged with the addon that provides it (when known) so
21
+ * the fan-out can honour the operator's per-destination toggle.
22
+ */
12
23
  private readonly destinations;
24
+ /**
25
+ * "Is this destination enabled?", injected by the wiring side (which owns
26
+ * the capability registry). Absent ⇒ everything is enabled.
27
+ *
28
+ * WHY: the orchestrator's Enable/Disable toggle only added the addon to
29
+ * `disabledProviders` and NOTHING consulted it for `log-destination` — so
30
+ * console and winston could not be turned off at all and the badge in the UI
31
+ * lied, while Loki appeared to work only because it carried a SECOND,
32
+ * private `enabled` setting of its own (audit 2026-07-30).
33
+ */
34
+ private isDestinationEnabled?;
13
35
  private readonly subscribers;
14
36
  private deviceNameLookup;
15
37
  /**
@@ -48,8 +70,17 @@ export declare class LogManager {
48
70
  * traffic starts. Lets a destination added mid-boot
49
71
  * still receive boot-time log entries.
50
72
  */
73
+ /** Apply new in-memory buffer limits at runtime (see PartitionedLogBuffer). */
74
+ reconfigureBuffer(options: {
75
+ readonly perAddonCapacity?: number;
76
+ readonly maxTotalEntries?: number | null;
77
+ readonly pruneLevel?: LogLevel;
78
+ }): void;
79
+ /** Set the per-destination enablement check (see {@link isDestinationEnabled}). */
80
+ setDestinationEnabledCheck(check: ((addonId: string) => boolean) | null): void;
51
81
  addDestination(dest: ILogDestination, opts?: {
52
82
  replay?: boolean;
83
+ addonId?: string;
53
84
  }): void;
54
85
  removeDestination(dest: ILogDestination): void;
55
86
  query(filter: LogFilter): LogEntry[];
@@ -42,12 +42,24 @@ export interface PartitionedLogBufferOptions {
42
42
  */
43
43
  export declare class PartitionedLogBuffer {
44
44
  private readonly buffers;
45
- private readonly perAddonCapacity;
46
- private readonly maxTotalEntries;
47
- private readonly pruneLevel;
45
+ private perAddonCapacity;
46
+ private maxTotalEntries;
47
+ private pruneLevel;
48
48
  /** Running total, so `push` does not walk every bucket to decide. */
49
49
  private totalEntries;
50
50
  constructor(perAddonCapacity?: number, options?: PartitionedLogBufferOptions);
51
+ /**
52
+ * Apply new limits at runtime. Shrinking takes effect as entries are pushed
53
+ * (each partition trims to the new capacity on its next write) — existing
54
+ * entries are NOT dropped eagerly: losing history the operator is currently
55
+ * reading, the instant they lower a number, is a worse surprise than a
56
+ * momentarily oversized buffer.
57
+ */
58
+ reconfigure(options: {
59
+ readonly perAddonCapacity?: number;
60
+ readonly maxTotalEntries?: number | null;
61
+ readonly pruneLevel?: LogLevel;
62
+ }): void;
51
63
  private bufferFor;
52
64
  push(entry: LogEntry): void;
53
65
  /**
@@ -3526,8 +3526,6 @@ function localEndpointPath(nodeId) {
3526
3526
  if (process.platform === "win32") return `\\\\.\\pipe\\camstack-${safe}`;
3527
3527
  return (0, node_path.join)((0, node_os.tmpdir)(), `camstack-${safe}.sock`);
3528
3528
  }
3529
- //#endregion
3530
- //#region src/kernel/transport/socket-channel.ts
3531
3529
  var SocketChannel = class {
3532
3530
  socket;
3533
3531
  nextId = 1;
@@ -3546,13 +3544,34 @@ var SocketChannel = class {
3546
3544
  socket.on("close", () => this.handleClose());
3547
3545
  socket.on("error", () => {});
3548
3546
  }
3549
- request(body) {
3547
+ /**
3548
+ * Send a request and wait for the peer's response.
3549
+ *
3550
+ * Bounded. Without a timer this settles on exactly two events — a matching
3551
+ * `res` frame, or the socket's `close` (which drains `pending`) — so a peer
3552
+ * that receives the request and then neither answers nor closes leaves the
3553
+ * caller pending forever. That is a wedged handler, or a half-open socket
3554
+ * after a child died without a clean teardown, and it is how camera 615 spent
3555
+ * 30+ minutes with every inference permit held by a call that was never
3556
+ * coming back.
3557
+ */
3558
+ request(body, opts) {
3550
3559
  if (this.closed) return Promise.reject(/* @__PURE__ */ new Error("channel closed"));
3551
3560
  const id = this.nextId++;
3561
+ const timeoutMs = opts?.timeoutMs ?? 6e4;
3552
3562
  return new Promise((resolve, reject) => {
3563
+ let timer = null;
3564
+ if (timeoutMs > 0) {
3565
+ timer = setTimeout(() => {
3566
+ this.pending.delete(id);
3567
+ reject(/* @__PURE__ */ new Error(`UDS request timed out after ${timeoutMs}ms`));
3568
+ }, timeoutMs);
3569
+ timer.unref?.();
3570
+ }
3553
3571
  this.pending.set(id, {
3554
3572
  resolve,
3555
- reject
3573
+ reject,
3574
+ timer
3556
3575
  });
3557
3576
  this.send({
3558
3577
  k: "req",
@@ -3616,6 +3635,7 @@ var SocketChannel = class {
3616
3635
  const p = this.pending.get(frame.id);
3617
3636
  if (!p) return;
3618
3637
  this.pending.delete(frame.id);
3638
+ if (p.timer !== null) clearTimeout(p.timer);
3619
3639
  if (frame.ok) p.resolve(frame.body);
3620
3640
  else p.reject(new Error(frame.err));
3621
3641
  return;
@@ -3626,7 +3646,10 @@ var SocketChannel = class {
3626
3646
  if (this.closeFired) return;
3627
3647
  this.closeFired = true;
3628
3648
  this.closed = true;
3629
- for (const [, p] of this.pending) p.reject(/* @__PURE__ */ new Error("channel closed"));
3649
+ for (const [, p] of this.pending) {
3650
+ if (p.timer !== null) clearTimeout(p.timer);
3651
+ p.reject(/* @__PURE__ */ new Error("channel closed"));
3652
+ }
3630
3653
  this.pending.clear();
3631
3654
  this.closeHandler();
3632
3655
  }
@@ -4303,6 +4326,10 @@ var LocalChildRegistry = class {
4303
4326
  resolveChildIdForAddon;
4304
4327
  /** This node's own Moleculer nodeId (see {@link LocalChildRegistryOptions.ownNodeId}). */
4305
4328
  ownNodeId;
4329
+ /** See {@link LocalChildRegistryOptions.isAggregatedCollectionMethod}. */
4330
+ isAggregatedCollectionMethod;
4331
+ /** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
4332
+ capTimeoutMs;
4306
4333
  /** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
4307
4334
  egressRoutedCaps = /* @__PURE__ */ new Set();
4308
4335
  /** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
@@ -4331,6 +4358,8 @@ var LocalChildRegistry = class {
4331
4358
  this.getActiveSingletonAddonId = opts.getActiveSingletonAddonId;
4332
4359
  this.resolveChildIdForAddon = opts.resolveChildIdForAddon;
4333
4360
  this.ownNodeId = opts.ownNodeId;
4361
+ this.isAggregatedCollectionMethod = opts.isAggregatedCollectionMethod;
4362
+ this.capTimeoutMs = opts.capTimeoutMs;
4334
4363
  } else {
4335
4364
  this.server = serverOrOptions;
4336
4365
  this.onUnownedCall = onUnownedCallArg;
@@ -4493,11 +4522,20 @@ var LocalChildRegistry = class {
4493
4522
  if (deviceId !== void 0 && entry.caps.some((cap) => cap.capName === capName && cap.deviceId === deviceId)) return true;
4494
4523
  return entry.caps.some((cap) => cap.capName === capName && cap.deviceId === void 0);
4495
4524
  }
4525
+ /**
4526
+ * Per-request options for a cap call: the cap method's declared `timeoutMs`
4527
+ * when one exists, else `undefined` so the channel applies its default.
4528
+ * Mirrors `CapRouteResolver.callTimeout` for the remote plane.
4529
+ */
4530
+ capRequestOpts(input) {
4531
+ const declared = this.capTimeoutMs?.(input.capName, input.method);
4532
+ return typeof declared === "number" ? { timeoutMs: declared } : void 0;
4533
+ }
4496
4534
  /** Forward a cap method call to a SPECIFIC child by id over UDS; rejects if that child is absent. */
4497
4535
  async callCapOnChild(childId, input) {
4498
4536
  const entry = this.children.get(childId);
4499
4537
  if (!entry) throw new Error(`no local child "${childId}" for cap "${input.capName}"`);
4500
- return entry.channel.request(this.toCapCall(input));
4538
+ return entry.channel.request(this.toCapCall(input), this.capRequestOpts(input));
4501
4539
  }
4502
4540
  /** Forward a cap method call to the owning child over UDS; rejects if none. */
4503
4541
  async callCap(input) {
@@ -4507,7 +4545,7 @@ var LocalChildRegistry = class {
4507
4545
  const where = input.deviceId === void 0 ? "" : ` for device ${input.deviceId}`;
4508
4546
  throw new Error(`no local child provides cap "${input.capName}"${where}`);
4509
4547
  }
4510
- return entry.channel.request(this.toCapCall(input));
4548
+ return entry.channel.request(this.toCapCall(input), this.capRequestOpts(input));
4511
4549
  }
4512
4550
  /**
4513
4551
  * Forward an ADDON-LEVEL call (routes / custom-action) to a SPECIFIC child
@@ -4694,7 +4732,7 @@ var LocalChildRegistry = class {
4694
4732
  };
4695
4733
  const pinnedNodeId = out.nodeId ?? extractNodeId(out.args);
4696
4734
  const pinTargetsThisNode = pinnedNodeId !== void 0 && this.ownNodeId !== void 0 && pinnedNodeId === this.ownNodeId;
4697
- if ((pinnedNodeId === void 0 || pinTargetsThisNode ? this.resolveChildId(out.capName, out.deviceId) : null) !== null) {
4735
+ if ((!(pinnedNodeId === void 0 && this.isAggregatedCollectionMethod?.(out.capName, out.method) === true) && (pinnedNodeId === void 0 || pinTargetsThisNode) ? this.resolveChildId(out.capName, out.deviceId) : null) !== null) {
4698
4736
  if (!this.egressRoutedCaps.has(out.capName)) {
4699
4737
  this.egressRoutedCaps.add(out.capName);
4700
4738
  this.logger?.info("routed child egress over UDS", { capName: out.capName });
@@ -5250,6 +5288,8 @@ function createParentUnownedCallHandler(deps) {
5250
5288
  if (nodeId === void 0) {
5251
5289
  const empty = deps.resolveEmptyCollection?.(input.capName, input.method);
5252
5290
  if (empty != null) return empty;
5291
+ const aggregate = await deps.callCollectionAggregate?.(input.capName, input.method, input.args);
5292
+ if (aggregate != null) return aggregate;
5253
5293
  }
5254
5294
  const resolver = deps.getResolver();
5255
5295
  if (resolver !== null) try {
@@ -5417,14 +5457,18 @@ function localProviderLink(resolver, observerOpts) {
5417
5457
  return ({ op, next }) => {
5418
5458
  const parsed = parsePath(op.path);
5419
5459
  if (!parsed) return next(op);
5460
+ const opWithDefaults = op.input === void 0 ? op : {
5461
+ ...op,
5462
+ input: (0, _camstack_types_addon.withCapInputDefaults)(parsed.capName, parsed.method, op.input)
5463
+ };
5420
5464
  if (localBase !== void 0) {
5421
5465
  const pinnedNodeId = (0, _camstack_types_addon.readNodePin)(op.context);
5422
- if (pinnedNodeId !== void 0 && pinnedNodeId !== localBase) return next(op);
5466
+ if (pinnedNodeId !== void 0 && pinnedNodeId !== localBase) return next(opWithDefaults);
5423
5467
  }
5424
5468
  const provider = resolver.getByName(parsed.capName);
5425
- if (!provider || typeof provider !== "object") return next(op);
5469
+ if (!provider || typeof provider !== "object") return next(opWithDefaults);
5426
5470
  const fn = Reflect.get(provider, parsed.method);
5427
- if (typeof fn !== "function") return next(op);
5471
+ if (typeof fn !== "function") return next(opWithDefaults);
5428
5472
  if (observerOpts) try {
5429
5473
  const providerAddonId = observerOpts.providerAddonIdForCap(parsed.capName);
5430
5474
  if (providerAddonId) observerOpts.observer({
@@ -5436,7 +5480,7 @@ function localProviderLink(resolver, observerOpts) {
5436
5480
  });
5437
5481
  } catch {}
5438
5482
  return observable((observer) => {
5439
- Promise.resolve(fn.call(provider, op.input)).then((data) => {
5483
+ Promise.resolve(fn.call(provider, opWithDefaults.input)).then((data) => {
5440
5484
  observer.next({ result: {
5441
5485
  type: "data",
5442
5486
  data