@camstack/server 1.1.65 → 1.1.66

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.
@@ -2243,6 +2243,33 @@ function createCapRouter_deviceExport(getProvider, createRemoteProxy) {
2243
2243
  }
2244
2244
  function createCapRouter_deviceManager(getProvider, createRemoteProxy) {
2245
2245
  return (0, trpc_middleware_js_1.trpcRouter)({
2246
+ getDeviceSettingsContribution: trpc_middleware_js_1.protectedProcedure
2247
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.input.loose())
2248
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.output)
2249
+ .query(async ({ input, ctx }) => {
2250
+ const { nodeId, ...methodInput } = input;
2251
+ const p = resolveProvider('device-manager', nodeId, () => getProvider(ctx), createRemoteProxy);
2252
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
2253
+ return p.getDeviceSettingsContribution(methodInput);
2254
+ }),
2255
+ getDeviceLiveContribution: trpc_middleware_js_1.protectedProcedure
2256
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.input.loose())
2257
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.output)
2258
+ .query(async ({ input, ctx }) => {
2259
+ const { nodeId, ...methodInput } = input;
2260
+ const p = resolveProvider('device-manager', nodeId, () => getProvider(ctx), createRemoteProxy);
2261
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
2262
+ return p.getDeviceLiveContribution(methodInput);
2263
+ }),
2264
+ applyDeviceSettingsPatch: trpc_middleware_js_1.adminProcedure
2265
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.input.loose())
2266
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.output)
2267
+ .mutation(async ({ input, ctx }) => {
2268
+ const { nodeId, ...methodInput } = input;
2269
+ const p = resolveProvider('device-manager', nodeId, () => getProvider(ctx), createRemoteProxy);
2270
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
2271
+ return p.applyDeviceSettingsPatch(methodInput);
2272
+ }),
2246
2273
  allocateDeviceId: trpc_middleware_js_1.protectedProcedure
2247
2274
  .input(types_39.deviceManagerCapability.methods.allocateDeviceId.input.loose())
2248
2275
  .output(types_39.deviceManagerCapability.methods.allocateDeviceId.output)
@@ -2511,6 +2538,15 @@ function createCapRouter_deviceManager(getProvider, createRemoteProxy) {
2511
2538
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
2512
2539
  return p.getChildren(methodInput);
2513
2540
  }),
2541
+ getLinkedDevices: trpc_middleware_js_1.protectedProcedure
2542
+ .input(types_39.deviceManagerCapability.methods.getLinkedDevices.input.loose())
2543
+ .output(types_39.deviceManagerCapability.methods.getLinkedDevices.output)
2544
+ .query(async ({ input, ctx }) => {
2545
+ const { nodeId, ...methodInput } = input;
2546
+ const p = resolveProvider('device-manager', nodeId, () => getProvider(ctx), createRemoteProxy);
2547
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
2548
+ return p.getLinkedDevices(methodInput);
2549
+ }),
2514
2550
  getStreamSources: trpc_middleware_js_1.protectedProcedure
2515
2551
  .input(types_39.deviceManagerCapability.methods.getStreamSources.input.loose())
2516
2552
  .output(types_39.deviceManagerCapability.methods.getStreamSources.output)
@@ -3117,6 +3153,33 @@ function createCapRouter_doorbell(getProvider, createRemoteProxy) {
3117
3153
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
3118
3154
  return p.getStatus(methodInput);
3119
3155
  }),
3156
+ getDeviceSettingsContribution: trpc_middleware_js_1.protectedProcedure
3157
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.input.loose())
3158
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceSettingsContribution.output)
3159
+ .query(async ({ input, ctx }) => {
3160
+ const { nodeId, ...methodInput } = input;
3161
+ const p = resolveProvider('doorbell', nodeId, () => getProvider(ctx), createRemoteProxy);
3162
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
3163
+ return p.getDeviceSettingsContribution(methodInput);
3164
+ }),
3165
+ getDeviceLiveContribution: trpc_middleware_js_1.protectedProcedure
3166
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.input.loose())
3167
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.getDeviceLiveContribution.output)
3168
+ .query(async ({ input, ctx }) => {
3169
+ const { nodeId, ...methodInput } = input;
3170
+ const p = resolveProvider('doorbell', nodeId, () => getProvider(ctx), createRemoteProxy);
3171
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
3172
+ return p.getDeviceLiveContribution(methodInput);
3173
+ }),
3174
+ applyDeviceSettingsPatch: trpc_middleware_js_1.adminProcedure
3175
+ .input(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.input.loose())
3176
+ .output(types_1.DEVICE_SETTINGS_CONTRIBUTION_METHODS.applyDeviceSettingsPatch.output)
3177
+ .mutation(async ({ input, ctx }) => {
3178
+ const { nodeId, ...methodInput } = input;
3179
+ const p = resolveProvider('doorbell', nodeId, () => getProvider(ctx), createRemoteProxy);
3180
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
3181
+ return p.applyDeviceSettingsPatch(methodInput);
3182
+ }),
3120
3183
  });
3121
3184
  }
3122
3185
  function createCapRouter_embeddingEncoder(getProvider, createRemoteProxy) {
@@ -5121,6 +5184,15 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
5121
5184
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5122
5185
  return p.listTracks(methodInput);
5123
5186
  }),
5187
+ listRecentTracks: trpc_middleware_js_1.protectedProcedure
5188
+ .input(types_78.pipelineAnalyticsCapability.methods.listRecentTracks.input.loose())
5189
+ .output(types_78.pipelineAnalyticsCapability.methods.listRecentTracks.output)
5190
+ .query(async ({ input, ctx }) => {
5191
+ const { nodeId, ...methodInput } = input;
5192
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
5193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5194
+ return p.listRecentTracks(methodInput);
5195
+ }),
5124
5196
  clearTracks: trpc_middleware_js_1.adminProcedure
5125
5197
  .input(types_78.pipelineAnalyticsCapability.methods.clearTracks.input.loose())
5126
5198
  .output(types_78.pipelineAnalyticsCapability.methods.clearTracks.output)
@@ -5157,6 +5229,24 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
5157
5229
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5158
5230
  return p.getAudioEvents(methodInput);
5159
5231
  }),
5232
+ listEventKinds: trpc_middleware_js_1.protectedProcedure
5233
+ .input(types_78.pipelineAnalyticsCapability.methods.listEventKinds.input.loose())
5234
+ .output(types_78.pipelineAnalyticsCapability.methods.listEventKinds.output)
5235
+ .query(async ({ input, ctx }) => {
5236
+ const { nodeId, ...methodInput } = input;
5237
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
5238
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5239
+ return p.listEventKinds(methodInput);
5240
+ }),
5241
+ getSensorEvents: trpc_middleware_js_1.protectedProcedure
5242
+ .input(types_78.pipelineAnalyticsCapability.methods.getSensorEvents.input.loose())
5243
+ .output(types_78.pipelineAnalyticsCapability.methods.getSensorEvents.output)
5244
+ .query(async ({ input, ctx }) => {
5245
+ const { nodeId, ...methodInput } = input;
5246
+ const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
5247
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
5248
+ return p.getSensorEvents(methodInput);
5249
+ }),
5160
5250
  getKeyEvents: trpc_middleware_js_1.protectedProcedure
5161
5251
  .input(types_78.pipelineAnalyticsCapability.methods.getKeyEvents.input.loose())
5162
5252
  .output(types_78.pipelineAnalyticsCapability.methods.getKeyEvents.output)
@@ -39,6 +39,8 @@ exports.shouldEmitProviderRegisteredReady = shouldEmitProviderRegisteredReady;
39
39
  const os = __importStar(require("node:os"));
40
40
  const addon_row_manifest_1 = require("./addon-row-manifest");
41
41
  const runner_convergence_1 = require("./runner-convergence");
42
+ const system_addons_sync_1 = require("./system-addons-sync");
43
+ const package_dir_utils_1 = require("./package-dir-utils");
42
44
  const types_1 = require("@camstack/types");
43
45
  const system_1 = require("@camstack/system");
44
46
  const system_2 = require("@camstack/system");
@@ -433,6 +435,24 @@ class AddonRegistryService {
433
435
  // launcher). Defaults to `<dataDir>/addons` for dev.
434
436
  const dataDir = path.resolve(process.env.CAMSTACK_DATA ?? 'camstack-data');
435
437
  const addonsDir = process.env.CAMSTACK_ADDONS_DIR ?? path.resolve(dataDir, 'addons');
438
+ // Builtins load from the ADDONS-DIR copy of `@camstack/system`, which no
439
+ // update channel refreshes on an image hub (seed excludes it, apply-update
440
+ // swaps only server-root, deploy of system is rejected) — a stale copy
441
+ // silently pins builtin code forever (2026-07-17: snapshot builtin ran
442
+ // 1.1.49 while the closure carried 1.1.51). Reconcile it from the hub's
443
+ // own closure when the closure is NEWER; a newer addons copy (dev
444
+ // live-update flow) is left alone. Never throws.
445
+ const closureSystemDir = (0, package_dir_utils_1.resolveHubClosurePackageDir)('@camstack/system');
446
+ if (closureSystemDir) {
447
+ const outcome = (0, system_addons_sync_1.syncSystemAddonsCopy)({
448
+ addonsDir,
449
+ closureSystemDir,
450
+ log: (msg, meta) => this.logger.info(msg, { meta: meta ?? {} }),
451
+ });
452
+ if (outcome === 'failed') {
453
+ this.logger.warn('system addons-copy sync failed — builtins may run stale code');
454
+ }
455
+ }
436
456
  await this.addonLoader.loadFromDirectory(addonsDir);
437
457
  // Hand pre-init load failures (broken package.json, missing
438
458
  // dist, import-time errors) to the health monitor so its retry
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.isVersionNewer = isVersionNewer;
37
+ exports.syncSystemAddonsCopy = syncSystemAddonsCopy;
38
+ /**
39
+ * system-addons-sync — reconcile the ADDONS-DIR copy of `@camstack/system`
40
+ * with the hub's own (active server-root closure) copy at boot.
41
+ *
42
+ * Builtins are loaded from `CAMSTACK_ADDONS_DIR/@camstack/system` (the addon
43
+ * loader scans only that dir), but NO update channel refreshes that copy on an
44
+ * image hub: the seed-addons stage excludes framework packages, applyServerUpdate
45
+ * swaps only /data/server-root, and `camstack deploy packages/system` is
46
+ * rejected once a release image runs. Live incident 2026-07-17: the snapshot
47
+ * builtin ran system 1.1.49 (no media endpoint) while the active closure
48
+ * carried 1.1.51 — shipped builtin code silently never executed.
49
+ *
50
+ * The sync copies `dist/` + `package.json` from the closure copy over the
51
+ * addons copy when the closure version is NEWER (semver-wise). The addons
52
+ * copy's own `node_modules/` is preserved: third-party deps also resolve via
53
+ * NODE_PATH (the framework dir), and `@camstack/*` deps are host-provided.
54
+ * Staged copy + rename swap so a crash mid-sync never leaves a gutted dist.
55
+ * An addons copy that is newer or equal (dev live-update flow) is left alone.
56
+ */
57
+ const fs = __importStar(require("node:fs"));
58
+ const path = __importStar(require("node:path"));
59
+ /** Loose semver compare on dotted numeric parts; non-numeric parts compare 0. */
60
+ function isVersionNewer(candidate, current) {
61
+ const a = candidate.split('.').map((p) => Number.parseInt(p, 10) || 0);
62
+ const b = current.split('.').map((p) => Number.parseInt(p, 10) || 0);
63
+ for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
64
+ const d = (a[i] ?? 0) - (b[i] ?? 0);
65
+ if (d !== 0)
66
+ return d > 0;
67
+ }
68
+ return false;
69
+ }
70
+ function readVersion(pkgDir) {
71
+ try {
72
+ const raw = JSON.parse(fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf-8'));
73
+ return typeof raw.version === 'string' ? raw.version : null;
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ /**
80
+ * Reconcile once. Returns what happened (for the caller's log/telemetry).
81
+ * Never throws — a failed sync leaves the previous copy running (same as
82
+ * before this fix existed) and reports `'failed'`.
83
+ */
84
+ function syncSystemAddonsCopy(input) {
85
+ const { addonsDir, closureSystemDir, log } = input;
86
+ const addonsCopyDir = path.join(addonsDir, '@camstack', 'system');
87
+ if (!fs.existsSync(path.join(addonsCopyDir, 'package.json')))
88
+ return 'absent';
89
+ const closureVersion = readVersion(closureSystemDir);
90
+ const addonsVersion = readVersion(addonsCopyDir);
91
+ if (closureVersion === null || addonsVersion === null)
92
+ return 'failed';
93
+ if (!isVersionNewer(closureVersion, addonsVersion))
94
+ return 'up-to-date';
95
+ try {
96
+ const srcDist = path.join(closureSystemDir, 'dist');
97
+ const nextDist = path.join(addonsCopyDir, `.dist.next-${process.pid}`);
98
+ const oldDist = path.join(addonsCopyDir, `.dist.old-${process.pid}`);
99
+ fs.rmSync(nextDist, { recursive: true, force: true });
100
+ fs.cpSync(srcDist, nextDist, { recursive: true });
101
+ // Swap: rename-aside then rename-in (metadata ops on the same mount).
102
+ fs.rmSync(oldDist, { recursive: true, force: true });
103
+ if (fs.existsSync(path.join(addonsCopyDir, 'dist'))) {
104
+ fs.renameSync(path.join(addonsCopyDir, 'dist'), oldDist);
105
+ }
106
+ fs.renameSync(nextDist, path.join(addonsCopyDir, 'dist'));
107
+ fs.copyFileSync(path.join(closureSystemDir, 'package.json'), path.join(addonsCopyDir, 'package.json'));
108
+ fs.rmSync(oldDist, { recursive: true, force: true });
109
+ log('addons-dir @camstack/system synced from closure', {
110
+ from: addonsVersion,
111
+ to: closureVersion,
112
+ });
113
+ return 'synced';
114
+ }
115
+ catch (err) {
116
+ log('addons-dir @camstack/system sync FAILED — stale builtins keep running', {
117
+ error: err instanceof Error ? err.message : String(err),
118
+ });
119
+ return 'failed';
120
+ }
121
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.65",
3
+ "version": "1.1.66",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",
@@ -23,19 +23,19 @@
23
23
  "test:watch": "vitest"
24
24
  },
25
25
  "dependencies": {
26
- "@camstack/addon-admin-ui": "1.1.53",
27
- "@camstack/addon-advanced-notifier": "1.1.25",
28
- "@camstack/addon-auth": "1.1.10",
29
- "@camstack/addon-decoder-nodeav": "1.1.13",
30
- "@camstack/addon-notifiers": "1.1.25",
31
- "@camstack/addon-pipeline": "1.1.58",
32
- "@camstack/addon-pipeline-orchestrator": "1.1.48",
33
- "@camstack/addon-post-analysis": "1.1.30",
34
- "@camstack/sdk": "1.1.25",
35
- "@camstack/shm-ring": "1.0.24",
36
- "@camstack/system": "1.1.51",
37
- "@camstack/types": "1.1.46",
38
- "@camstack/ui-library": "1.1.37",
26
+ "@camstack/addon-admin-ui": "1.1.54",
27
+ "@camstack/addon-advanced-notifier": "1.1.26",
28
+ "@camstack/addon-auth": "1.1.11",
29
+ "@camstack/addon-decoder-nodeav": "1.1.14",
30
+ "@camstack/addon-notifiers": "1.1.26",
31
+ "@camstack/addon-pipeline": "1.1.59",
32
+ "@camstack/addon-pipeline-orchestrator": "1.1.49",
33
+ "@camstack/addon-post-analysis": "1.1.31",
34
+ "@camstack/sdk": "1.1.26",
35
+ "@camstack/shm-ring": "1.0.25",
36
+ "@camstack/system": "1.1.52",
37
+ "@camstack/types": "1.1.47",
38
+ "@camstack/ui-library": "1.1.38",
39
39
  "@fastify/compress": "^9.0.0",
40
40
  "@fastify/cookie": "^11.0.2",
41
41
  "@fastify/multipart": "^10.0.0",