@camstack/server 1.2.25 → 1.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/main.js +5 -0
- package/dist/api/trpc/cap-router-runtime.js +33 -0
- package/dist/api/trpc/generated-cap-routers.js +97 -0
- package/dist/core/addon/addon-registry.service.js +6 -1
- package/dist/core/moleculer/moleculer.service.js +25 -0
- package/dist/manual-boot.js +5 -0
- package/package.json +8 -8
package/dist/agent/main.js
CHANGED
|
@@ -322,6 +322,11 @@ async function startAgent(configPath) {
|
|
|
322
322
|
const agentCapabilities = [
|
|
323
323
|
types_2.storageCapability,
|
|
324
324
|
types_2.storageProviderCapability,
|
|
325
|
+
// The path browser for "add a storage location on this node" — the agent
|
|
326
|
+
// registers the provider since day one, but without DECLARING the cap
|
|
327
|
+
// here the hub's manifest never learns of it and node-routed browse
|
|
328
|
+
// answers "not available on node X" (2026-07-30 fix).
|
|
329
|
+
types_2.filesystemBrowseCapability,
|
|
325
330
|
types_2.settingsStoreCapability,
|
|
326
331
|
types_2.logDestinationCapability,
|
|
327
332
|
types_2.metricsProviderCapability,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
23
|
exports.COLLECTION_ARRAY_METHODS = void 0;
|
|
24
|
+
exports.aggregateCollectionCall = aggregateCollectionCall;
|
|
24
25
|
exports.createCapRouterPrimitives = createCapRouterPrimitives;
|
|
25
26
|
exports.createCapRouterServices = createCapRouterServices;
|
|
26
27
|
exports.buildRuntimeCapRouters = buildRuntimeCapRouters;
|
|
@@ -86,6 +87,38 @@ function resolveCollectionProvider(reg, capName, addonId) {
|
|
|
86
87
|
}
|
|
87
88
|
return aggregate;
|
|
88
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The collection UNION for a cap call arriving OUTSIDE the tRPC router — a
|
|
92
|
+
* forked addon's `ctx.api.<cap>.<method>` reaching the parent's
|
|
93
|
+
* `onUnownedCall`. Returns `null` when `(capName, method)` is not an
|
|
94
|
+
* aggregated collection array-method, so the caller routes normally.
|
|
95
|
+
*
|
|
96
|
+
* Exists because routing resolves ONE provider while this router fans array
|
|
97
|
+
* methods across ALL of them: the two answers disagreed, and for
|
|
98
|
+
* `notification-output` the routed one was empty — which the Notification
|
|
99
|
+
* Center read as "target deleted" and turned into permanent dead-letters for
|
|
100
|
+
* every notification it ever produced (2026-07-30). Sharing
|
|
101
|
+
* {@link resolveCollectionProvider} keeps the two paths from drifting again.
|
|
102
|
+
*
|
|
103
|
+
* `null` on zero providers too: that is the empty-collection fast-path's job
|
|
104
|
+
* (it answers `[]` without routing), not this one's.
|
|
105
|
+
*/
|
|
106
|
+
async function aggregateCollectionCall(reg, capName, method, args) {
|
|
107
|
+
if (!reg)
|
|
108
|
+
return null;
|
|
109
|
+
if (reg.getDefinition(capName)?.mode !== 'collection')
|
|
110
|
+
return null;
|
|
111
|
+
if (!exports.COLLECTION_ARRAY_METHODS.get(capName)?.includes(method))
|
|
112
|
+
return null;
|
|
113
|
+
if (reg.getCollectionEntries(capName).length === 0)
|
|
114
|
+
return null;
|
|
115
|
+
const aggregate = resolveCollectionProvider(reg, capName, undefined);
|
|
116
|
+
const fn = aggregate?.[method];
|
|
117
|
+
if (typeof fn !== 'function')
|
|
118
|
+
return null;
|
|
119
|
+
const out = await fn(args);
|
|
120
|
+
return Array.isArray(out) ? out : null;
|
|
121
|
+
}
|
|
89
122
|
/**
|
|
90
123
|
* Fan an array-returning method across every provider and flatten the
|
|
91
124
|
* results — the runtime equivalent of `concatCollection` for the
|
|
@@ -4043,6 +4043,22 @@ function createCapRouter_localNetwork(getProvider, createRemoteProxy) {
|
|
|
4043
4043
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4044
4044
|
return p.getConnectionEndpoints(methodInput);
|
|
4045
4045
|
}),
|
|
4046
|
+
getNotificationEndpoint: trpc_middleware_js_1.protectedProcedure
|
|
4047
|
+
.input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
|
|
4048
|
+
.output(types_54.localNetworkCapability.methods.getNotificationEndpoint.output)
|
|
4049
|
+
.query(async ({ input, ctx }) => {
|
|
4050
|
+
const p = resolveProvider('local-network', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4051
|
+
return p.getNotificationEndpoint();
|
|
4052
|
+
}),
|
|
4053
|
+
setNotificationEndpoint: trpc_middleware_js_1.protectedProcedure
|
|
4054
|
+
.input(types_54.localNetworkCapability.methods.setNotificationEndpoint.input.loose())
|
|
4055
|
+
.output(types_54.localNetworkCapability.methods.setNotificationEndpoint.output)
|
|
4056
|
+
.mutation(async ({ input, ctx }) => {
|
|
4057
|
+
const { nodeId, ...methodInput } = input;
|
|
4058
|
+
const p = resolveProvider('local-network', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4059
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4060
|
+
return p.setNotificationEndpoint(methodInput);
|
|
4061
|
+
}),
|
|
4046
4062
|
getAllowedAddresses: trpc_middleware_js_1.protectedProcedure
|
|
4047
4063
|
.input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
|
|
4048
4064
|
.output(types_54.localNetworkCapability.methods.getAllowedAddresses.output)
|
|
@@ -5387,6 +5403,33 @@ function createCapRouter_pipelineAnalytics(getProvider, createRemoteProxy) {
|
|
|
5387
5403
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
5388
5404
|
return p.deleteDeviceEvents(methodInput);
|
|
5389
5405
|
}),
|
|
5406
|
+
relocateMedia: trpc_middleware_js_1.adminProcedure
|
|
5407
|
+
.input(types_78.pipelineAnalyticsCapability.methods.relocateMedia.input.loose())
|
|
5408
|
+
.output(types_78.pipelineAnalyticsCapability.methods.relocateMedia.output)
|
|
5409
|
+
.mutation(async ({ input, ctx }) => {
|
|
5410
|
+
const { nodeId, ...methodInput } = input;
|
|
5411
|
+
const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
5412
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
5413
|
+
return p.relocateMedia(methodInput);
|
|
5414
|
+
}),
|
|
5415
|
+
getMediaRelocateStatus: trpc_middleware_js_1.adminProcedure
|
|
5416
|
+
.input(types_78.pipelineAnalyticsCapability.methods.getMediaRelocateStatus.input.loose())
|
|
5417
|
+
.output(types_78.pipelineAnalyticsCapability.methods.getMediaRelocateStatus.output)
|
|
5418
|
+
.query(async ({ input, ctx }) => {
|
|
5419
|
+
const { nodeId, ...methodInput } = input;
|
|
5420
|
+
const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
5421
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
5422
|
+
return p.getMediaRelocateStatus(methodInput);
|
|
5423
|
+
}),
|
|
5424
|
+
cancelMediaRelocate: trpc_middleware_js_1.adminProcedure
|
|
5425
|
+
.input(types_78.pipelineAnalyticsCapability.methods.cancelMediaRelocate.input.loose())
|
|
5426
|
+
.output(types_78.pipelineAnalyticsCapability.methods.cancelMediaRelocate.output)
|
|
5427
|
+
.mutation(async ({ input, ctx }) => {
|
|
5428
|
+
const { nodeId, ...methodInput } = input;
|
|
5429
|
+
const p = resolveProvider('pipeline-analytics', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
5430
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
5431
|
+
return p.cancelMediaRelocate(methodInput);
|
|
5432
|
+
}),
|
|
5390
5433
|
listOpsLog: trpc_middleware_js_1.adminProcedure
|
|
5391
5434
|
.input(types_78.pipelineAnalyticsCapability.methods.listOpsLog.input.loose())
|
|
5392
5435
|
.output(types_78.pipelineAnalyticsCapability.methods.listOpsLog.output)
|
|
@@ -6725,6 +6768,51 @@ function createCapRouter_recording(getProvider, createRemoteProxy) {
|
|
|
6725
6768
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6726
6769
|
return p.listOpsLog(methodInput);
|
|
6727
6770
|
}),
|
|
6771
|
+
renderGif: trpc_middleware_js_1.adminProcedure
|
|
6772
|
+
.input(types_88.recordingCapability.methods.renderGif.input.loose())
|
|
6773
|
+
.output(types_88.recordingCapability.methods.renderGif.output)
|
|
6774
|
+
.mutation(async ({ input, ctx }) => {
|
|
6775
|
+
const { nodeId, ...methodInput } = input;
|
|
6776
|
+
const p = resolveProvider('recording', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
6777
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6778
|
+
return p.renderGif(methodInput);
|
|
6779
|
+
}),
|
|
6780
|
+
renderClip: trpc_middleware_js_1.adminProcedure
|
|
6781
|
+
.input(types_88.recordingCapability.methods.renderClip.input.loose())
|
|
6782
|
+
.output(types_88.recordingCapability.methods.renderClip.output)
|
|
6783
|
+
.mutation(async ({ input, ctx }) => {
|
|
6784
|
+
const { nodeId, ...methodInput } = input;
|
|
6785
|
+
const p = resolveProvider('recording', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
6786
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6787
|
+
return p.renderClip(methodInput);
|
|
6788
|
+
}),
|
|
6789
|
+
relocateFootage: trpc_middleware_js_1.adminProcedure
|
|
6790
|
+
.input(types_88.recordingCapability.methods.relocateFootage.input.loose())
|
|
6791
|
+
.output(types_88.recordingCapability.methods.relocateFootage.output)
|
|
6792
|
+
.mutation(async ({ input, ctx }) => {
|
|
6793
|
+
const { nodeId, ...methodInput } = input;
|
|
6794
|
+
const p = resolveProvider('recording', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
6795
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6796
|
+
return p.relocateFootage(methodInput);
|
|
6797
|
+
}),
|
|
6798
|
+
getRelocateStatus: trpc_middleware_js_1.adminProcedure
|
|
6799
|
+
.input(types_88.recordingCapability.methods.getRelocateStatus.input.loose())
|
|
6800
|
+
.output(types_88.recordingCapability.methods.getRelocateStatus.output)
|
|
6801
|
+
.query(async ({ input, ctx }) => {
|
|
6802
|
+
const { nodeId, ...methodInput } = input;
|
|
6803
|
+
const p = resolveProvider('recording', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
6804
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6805
|
+
return p.getRelocateStatus(methodInput);
|
|
6806
|
+
}),
|
|
6807
|
+
cancelRelocate: trpc_middleware_js_1.adminProcedure
|
|
6808
|
+
.input(types_88.recordingCapability.methods.cancelRelocate.input.loose())
|
|
6809
|
+
.output(types_88.recordingCapability.methods.cancelRelocate.output)
|
|
6810
|
+
.mutation(async ({ input, ctx }) => {
|
|
6811
|
+
const { nodeId, ...methodInput } = input;
|
|
6812
|
+
const p = resolveProvider('recording', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
6813
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
6814
|
+
return p.cancelRelocate(methodInput);
|
|
6815
|
+
}),
|
|
6728
6816
|
});
|
|
6729
6817
|
}
|
|
6730
6818
|
function createCapRouter_recordingExport(getProvider, createRemoteProxy) {
|
|
@@ -7587,6 +7675,15 @@ function createCapRouter_streamBroker(getProvider, createRemoteProxy) {
|
|
|
7587
7675
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
7588
7676
|
return p.unassignProfile(methodInput);
|
|
7589
7677
|
}),
|
|
7678
|
+
renderPreBufferClip: trpc_middleware_js_1.adminProcedure
|
|
7679
|
+
.input(types_100.streamBrokerCapability.methods.renderPreBufferClip.input.loose())
|
|
7680
|
+
.output(types_100.streamBrokerCapability.methods.renderPreBufferClip.output)
|
|
7681
|
+
.mutation(async ({ input, ctx }) => {
|
|
7682
|
+
const { nodeId, ...methodInput } = input;
|
|
7683
|
+
const p = resolveProvider('stream-broker', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
7684
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
7685
|
+
return p.renderPreBufferClip(methodInput);
|
|
7686
|
+
}),
|
|
7590
7687
|
listAllCameraStreams: trpc_middleware_js_1.protectedProcedure
|
|
7591
7688
|
.input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
|
|
7592
7689
|
.output(types_100.streamBrokerCapability.methods.listAllCameraStreams.output)
|
|
@@ -2266,7 +2266,9 @@ class AddonRegistryService {
|
|
|
2266
2266
|
const provider = this.capabilityRegistry.getProviderByAddon('log-destination', addonId);
|
|
2267
2267
|
if (!provider)
|
|
2268
2268
|
return;
|
|
2269
|
-
|
|
2269
|
+
// Tagged with the providing addon so the fan-out can honour the
|
|
2270
|
+
// operator's Enable/Disable toggle for THIS destination.
|
|
2271
|
+
this.loggingService.addDestination(provider, { addonId });
|
|
2270
2272
|
this.logger.info('Log destination added', { meta: { phase: 'v2' } });
|
|
2271
2273
|
break;
|
|
2272
2274
|
}
|
|
@@ -2711,6 +2713,9 @@ class AddonRegistryService {
|
|
|
2711
2713
|
// deviceId index. The per-device `getBindings` resolver prefers this
|
|
2712
2714
|
// over filtering the whole-cluster flat view.
|
|
2713
2715
|
listClusterNativeCapsForDevice: (deviceId) => this.moleculer.listClusterNativeCapsForDevice(deviceId),
|
|
2716
|
+
// Node-routed cap proxy — lets hub builtins (storage-orchestrator)
|
|
2717
|
+
// dispatch provider work to the node that OWNS the data.
|
|
2718
|
+
resolveNodeCapability: (capName, nodeId) => this.moleculer.createCapabilityProxy(capName, nodeId),
|
|
2714
2719
|
},
|
|
2715
2720
|
registerProvider,
|
|
2716
2721
|
resolveProvider: (capName) => {
|
|
@@ -290,6 +290,13 @@ class MoleculerService {
|
|
|
290
290
|
return null;
|
|
291
291
|
return [];
|
|
292
292
|
},
|
|
293
|
+
// Collection FAN-OUT for the same child→parent path: a collection
|
|
294
|
+
// array-method answers with the union across every provider, exactly
|
|
295
|
+
// as this server's tRPC cap-router does (shared code — the two must
|
|
296
|
+
// never disagree again). Routing alone picks ONE provider, which is
|
|
297
|
+
// how the Notification Center saw an empty `notification-output`
|
|
298
|
+
// catalog and dead-lettered every notification (2026-07-30).
|
|
299
|
+
callCollectionAggregate: (capName, method, args) => (0, cap_router_runtime_js_1.aggregateCollectionCall)(this.capabilityService.getRegistry(), capName, method, args),
|
|
293
300
|
// Hub-core `$`-service discriminant for the general
|
|
294
301
|
// provider-not-yet-registered recovery. A resolver miss on a NON-core
|
|
295
302
|
// cap (any addon-provided system/singleton cap, e.g.
|
|
@@ -322,6 +329,24 @@ class MoleculerService {
|
|
|
322
329
|
// onUnownedCall (a pin to ANOTHER node still bypasses the sibling).
|
|
323
330
|
ownNodeId: nodeId,
|
|
324
331
|
onUnownedCall,
|
|
332
|
+
// A collection ARRAY method must reach `onUnownedCall` (which fans it
|
|
333
|
+
// across every provider) instead of being short-circuited to ONE local
|
|
334
|
+
// sibling. Same predicate the aggregate itself uses, so the two agree
|
|
335
|
+
// by construction.
|
|
336
|
+
isAggregatedCollectionMethod: (capName, method) => {
|
|
337
|
+
const reg = this.capabilityService.getRegistry();
|
|
338
|
+
if (!reg)
|
|
339
|
+
return false;
|
|
340
|
+
if (reg.getDefinition(capName)?.mode !== 'collection')
|
|
341
|
+
return false;
|
|
342
|
+
return cap_router_runtime_js_1.COLLECTION_ARRAY_METHODS.get(capName)?.includes(method) === true;
|
|
343
|
+
},
|
|
344
|
+
// Bound every UDS cap call by the cap's own declared timeout, falling
|
|
345
|
+
// back to the channel default. Same resolver the REMOTE plane uses
|
|
346
|
+
// below, so a method that survives 16 minutes across nodes survives it
|
|
347
|
+
// across a socket too — and one that hangs is cut off on both.
|
|
348
|
+
capTimeoutMs: (capName, method) => this.capabilityService.getRegistry()?.getDefinition(capName)?.methods?.[method]
|
|
349
|
+
?.timeoutMs,
|
|
325
350
|
logger: {
|
|
326
351
|
info: (msg, meta) => logger.info(msg, meta !== null && meta !== undefined
|
|
327
352
|
? { meta: meta }
|
package/dist/manual-boot.js
CHANGED
|
@@ -114,6 +114,11 @@ async function bootManual(opts) {
|
|
|
114
114
|
// very first DeviceRegistered event populates the cache before any
|
|
115
115
|
// log line needing `deviceName` is emitted.
|
|
116
116
|
loggingService.attachDeviceNameStream(eventBusService);
|
|
117
|
+
// The orchestrator's per-destination Enable/Disable toggle becomes the ONE
|
|
118
|
+
// truth for every log destination — it used to be write-only (nothing read
|
|
119
|
+
// the disabled set), so console/winston could not be turned off at all while
|
|
120
|
+
// Loki appeared to work only through a second, private `enabled` setting.
|
|
121
|
+
loggingService.setDestinationEnabledCheck((addonId) => capabilityService.getRegistry()?.isProviderDisabled('log-destination', addonId) !== true);
|
|
117
122
|
const featureService = new feature_service_1.FeatureService(configService);
|
|
118
123
|
const authService = new auth_service_1.AuthService(configService);
|
|
119
124
|
const streamProbeService = new stream_probe_service_1.StreamProbeService(loggingService);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.27",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -33,19 +33,19 @@
|
|
|
33
33
|
]
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@camstack/addon-admin-ui": "1.2.
|
|
36
|
+
"@camstack/addon-admin-ui": "1.2.17",
|
|
37
37
|
"@camstack/addon-agent-ui": "1.2.6",
|
|
38
38
|
"@camstack/addon-auth": "1.2.6",
|
|
39
39
|
"@camstack/addon-decoder-nodeav": "1.2.6",
|
|
40
|
-
"@camstack/addon-notifiers": "1.2.
|
|
41
|
-
"@camstack/addon-pipeline": "1.2.
|
|
40
|
+
"@camstack/addon-notifiers": "1.2.8",
|
|
41
|
+
"@camstack/addon-pipeline": "1.2.28",
|
|
42
42
|
"@camstack/addon-pipeline-orchestrator": "1.2.11",
|
|
43
|
-
"@camstack/addon-post-analysis": "1.2.
|
|
43
|
+
"@camstack/addon-post-analysis": "1.2.18",
|
|
44
44
|
"@camstack/sdk": "1.2.6",
|
|
45
45
|
"@camstack/shm-ring": "1.1.6",
|
|
46
|
-
"@camstack/system": "1.2.
|
|
47
|
-
"@camstack/types": "1.2.
|
|
48
|
-
"@camstack/ui-library": "1.2.
|
|
46
|
+
"@camstack/system": "1.2.24",
|
|
47
|
+
"@camstack/types": "1.2.17",
|
|
48
|
+
"@camstack/ui-library": "1.2.13",
|
|
49
49
|
"@fastify/compress": "^9.0.0",
|
|
50
50
|
"@fastify/cookie": "^11.0.2",
|
|
51
51
|
"@fastify/cors": "^11.2.0",
|