@camstack/server 1.2.601 → 1.2.602
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/api/trpc/cap-router-runtime.js +54 -0
- package/dist/api/trpc/generated-cap-mounts.js +9 -2
- package/dist/api/trpc/generated-cap-routers.js +52 -16
- package/dist/api/trpc/trpc.router.js +9 -0
- package/dist/core/addon/addon-registry.service.js +42 -21
- package/dist/core/addon/hub-addon-api.js +27 -0
- package/package.json +14 -14
|
@@ -345,6 +345,54 @@ function createCapRouterPrimitives() {
|
|
|
345
345
|
iterableSubscription: trpc_middleware_js_1.iterableSubscription,
|
|
346
346
|
};
|
|
347
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* `device-adoption` is collection-scoped: without an explicit `{ addonId }`
|
|
350
|
+
* pin the router must NOT fall through to the first registered provider.
|
|
351
|
+
* Resolve the owning addon from `integrationId` (most methods) or
|
|
352
|
+
* `camDeviceId` (`resync` only).
|
|
353
|
+
*/
|
|
354
|
+
async function inferDeviceAdoptionCollectionAddonPin(methodName, input, deps) {
|
|
355
|
+
const integrationId = typeof input.integrationId === 'string' && input.integrationId.length > 0
|
|
356
|
+
? input.integrationId
|
|
357
|
+
: undefined;
|
|
358
|
+
const camDeviceId = typeof input.camDeviceId === 'number' && Number.isInteger(input.camDeviceId)
|
|
359
|
+
? input.camDeviceId
|
|
360
|
+
: undefined;
|
|
361
|
+
if (methodName === 'resync' || (camDeviceId !== undefined && integrationId === undefined)) {
|
|
362
|
+
if (camDeviceId === undefined) {
|
|
363
|
+
throw new server_1.TRPCError({
|
|
364
|
+
code: 'BAD_REQUEST',
|
|
365
|
+
message: 'deviceAdoption.resync requires camDeviceId (owning addon is resolved from it) or an explicit addonId pin.',
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
const resolved = deps.resolveDeviceAddonId
|
|
369
|
+
? await Promise.resolve(deps.resolveDeviceAddonId(camDeviceId))
|
|
370
|
+
: null;
|
|
371
|
+
if (resolved === null || resolved === '') {
|
|
372
|
+
throw new server_1.TRPCError({
|
|
373
|
+
code: 'BAD_REQUEST',
|
|
374
|
+
message: `deviceAdoption.${methodName}: device ${camDeviceId} not found — pass addonId explicitly.`,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
return resolved;
|
|
378
|
+
}
|
|
379
|
+
if (integrationId !== undefined) {
|
|
380
|
+
const resolved = deps.resolveIntegrationAddonId
|
|
381
|
+
? await Promise.resolve(deps.resolveIntegrationAddonId(integrationId))
|
|
382
|
+
: null;
|
|
383
|
+
if (resolved === null || resolved === '') {
|
|
384
|
+
throw new server_1.TRPCError({
|
|
385
|
+
code: 'BAD_REQUEST',
|
|
386
|
+
message: `deviceAdoption.${methodName}: unknown integrationId "${integrationId}" — pass addonId explicitly.`,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return resolved;
|
|
390
|
+
}
|
|
391
|
+
throw new server_1.TRPCError({
|
|
392
|
+
code: 'BAD_REQUEST',
|
|
393
|
+
message: `deviceAdoption.${methodName} requires addonId (top-level pin) or integrationId to resolve the owning provider.`,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
348
396
|
/** Build the `services` half of `buildCapRouters(primitives, services)`. */
|
|
349
397
|
function createCapRouterServices(deps) {
|
|
350
398
|
const reg = deps.capabilityRegistry;
|
|
@@ -419,10 +467,16 @@ function createCapRouterServices(deps) {
|
|
|
419
467
|
`An unresolvable addonId is refused rather than answered by another provider.`,
|
|
420
468
|
});
|
|
421
469
|
};
|
|
470
|
+
const inferCollectionAddonPin = (capName, methodName, methodInput) => {
|
|
471
|
+
if (capName !== 'device-adoption')
|
|
472
|
+
return undefined;
|
|
473
|
+
return inferDeviceAdoptionCollectionAddonPin(methodName, methodInput, deps);
|
|
474
|
+
};
|
|
422
475
|
return {
|
|
423
476
|
getLocalProvider,
|
|
424
477
|
remoteProxy,
|
|
425
478
|
rejectUnresolvedAddonPin,
|
|
479
|
+
inferCollectionAddonPin,
|
|
426
480
|
noProvider: (capName, nodeId) => {
|
|
427
481
|
if (nodeId !== undefined && nodeId !== 'hub') {
|
|
428
482
|
throw new server_1.TRPCError({
|
|
@@ -186,8 +186,15 @@ function mountAllCaps(services) {
|
|
|
186
186
|
decoder: (0, generated_cap_routers_js_1.createCapRouter_decoder)((_ctx) => reg?.getSingleton('decoder') ?? null, remoteCapProxy),
|
|
187
187
|
detectionPipeline: (0, generated_cap_routers_js_1.createCapRouter_detectionPipeline)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'detection-pipeline'), remoteCapProxy),
|
|
188
188
|
deviceAdminLink: (0, generated_cap_routers_js_1.createCapRouter_deviceAdminLink)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'device-admin-link'), remoteCapProxy),
|
|
189
|
-
deviceAdoption: (0, generated_cap_routers_js_1.createCapRouter_deviceAdoption)((_ctx) =>
|
|
190
|
-
|
|
189
|
+
deviceAdoption: (0, generated_cap_routers_js_1.createCapRouter_deviceAdoption)((_ctx, addonId) => {
|
|
190
|
+
if (!reg)
|
|
191
|
+
return null;
|
|
192
|
+
if (addonId !== undefined) {
|
|
193
|
+
return reg.getProviderByAddonId('device-adoption', addonId);
|
|
194
|
+
}
|
|
195
|
+
const entries = reg.getCollectionEntries('device-adoption');
|
|
196
|
+
return entries[0]?.[1] ?? null;
|
|
197
|
+
}, remoteCapProxy),
|
|
191
198
|
deviceCredentials: (0, generated_cap_routers_js_1.createCapRouter_deviceCredentials)((_ctx) => reg?.getSingleton('device-credentials') ?? null, remoteCapProxy),
|
|
192
199
|
deviceDiscovery: (0, generated_cap_routers_js_1.createCapRouter_deviceDiscovery)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'device-discovery'), remoteCapProxy),
|
|
193
200
|
deviceExport: (0, generated_cap_routers_js_1.createCapRouter_deviceExport)((_ctx, addonId) => {
|
|
@@ -2612,8 +2612,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2612
2612
|
.input(types_2.DEVICE_STATUS_METHOD.getStatus.input.loose())
|
|
2613
2613
|
.output(types_2.DEVICE_STATUS_METHOD.getStatus.output)
|
|
2614
2614
|
.query(async ({ input, ctx }) => {
|
|
2615
|
-
const { nodeId, ...methodInput } = input;
|
|
2616
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2615
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2616
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2617
2617
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2618
2618
|
return p.getStatus(methodInput);
|
|
2619
2619
|
}),
|
|
@@ -2621,8 +2621,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2621
2621
|
.input(types_45.deviceAdoptionCapability.methods.listCandidateFilters.input.loose())
|
|
2622
2622
|
.output(types_45.deviceAdoptionCapability.methods.listCandidateFilters.output)
|
|
2623
2623
|
.query(async ({ input, ctx }) => {
|
|
2624
|
-
const { nodeId, ...methodInput } = input;
|
|
2625
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2624
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2625
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2626
2626
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2627
2627
|
return p.listCandidateFilters(methodInput);
|
|
2628
2628
|
}),
|
|
@@ -2630,8 +2630,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2630
2630
|
.input(types_45.deviceAdoptionCapability.methods.listCandidates.input.loose())
|
|
2631
2631
|
.output(types_45.deviceAdoptionCapability.methods.listCandidates.output)
|
|
2632
2632
|
.query(async ({ input, ctx }) => {
|
|
2633
|
-
const { nodeId, ...methodInput } = input;
|
|
2634
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2633
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2634
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2635
2635
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2636
2636
|
return p.listCandidates(methodInput);
|
|
2637
2637
|
}),
|
|
@@ -2639,8 +2639,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2639
2639
|
.input(types_45.deviceAdoptionCapability.methods.getCandidate.input.loose())
|
|
2640
2640
|
.output(types_45.deviceAdoptionCapability.methods.getCandidate.output)
|
|
2641
2641
|
.query(async ({ input, ctx }) => {
|
|
2642
|
-
const { nodeId, ...methodInput } = input;
|
|
2643
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2642
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2643
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2644
2644
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2645
2645
|
return p.getCandidate(methodInput);
|
|
2646
2646
|
}),
|
|
@@ -2648,8 +2648,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2648
2648
|
.input(types_45.deviceAdoptionCapability.methods.refresh.input.loose())
|
|
2649
2649
|
.output(types_45.deviceAdoptionCapability.methods.refresh.output)
|
|
2650
2650
|
.mutation(async ({ input, ctx }) => {
|
|
2651
|
-
const { nodeId, ...methodInput } = input;
|
|
2652
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2651
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2652
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2653
2653
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2654
2654
|
return p.refresh(methodInput);
|
|
2655
2655
|
}),
|
|
@@ -2657,8 +2657,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2657
2657
|
.input(types_45.deviceAdoptionCapability.methods.adopt.input.loose())
|
|
2658
2658
|
.output(types_45.deviceAdoptionCapability.methods.adopt.output)
|
|
2659
2659
|
.mutation(async ({ input, ctx }) => {
|
|
2660
|
-
const { nodeId, ...methodInput } = input;
|
|
2661
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2660
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2661
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2662
2662
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2663
2663
|
return p.adopt(methodInput);
|
|
2664
2664
|
}),
|
|
@@ -2666,8 +2666,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2666
2666
|
.input(types_45.deviceAdoptionCapability.methods.release.input.loose())
|
|
2667
2667
|
.output(types_45.deviceAdoptionCapability.methods.release.output)
|
|
2668
2668
|
.mutation(async ({ input, ctx }) => {
|
|
2669
|
-
const { nodeId, ...methodInput } = input;
|
|
2670
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2669
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2670
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2671
2671
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2672
2672
|
return p.release(methodInput);
|
|
2673
2673
|
}),
|
|
@@ -2675,8 +2675,8 @@ function createCapRouter_deviceAdoption(getProvider, createRemoteProxy) {
|
|
|
2675
2675
|
.input(types_45.deviceAdoptionCapability.methods.resync.input.loose())
|
|
2676
2676
|
.output(types_45.deviceAdoptionCapability.methods.resync.output)
|
|
2677
2677
|
.mutation(async ({ input, ctx }) => {
|
|
2678
|
-
const { nodeId, ...methodInput } = input;
|
|
2679
|
-
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
2678
|
+
const { nodeId, addonId, ...methodInput } = input;
|
|
2679
|
+
const p = resolveProvider('device-adoption', nodeId, () => getProvider(ctx, addonId), createRemoteProxy);
|
|
2680
2680
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
2681
2681
|
return p.resync(methodInput);
|
|
2682
2682
|
}),
|
|
@@ -4314,6 +4314,42 @@ function createCapRouter_dishwasher(getProvider, createRemoteProxy) {
|
|
|
4314
4314
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4315
4315
|
return p.setHygienePlus(methodInput);
|
|
4316
4316
|
}),
|
|
4317
|
+
setExtraDry: trpc_middleware_js_1.protectedProcedure
|
|
4318
|
+
.input(types_56.dishwasherCapability.methods.setExtraDry.input.loose())
|
|
4319
|
+
.output(types_56.dishwasherCapability.methods.setExtraDry.output)
|
|
4320
|
+
.mutation(async ({ input, ctx }) => {
|
|
4321
|
+
const { nodeId, ...methodInput } = input;
|
|
4322
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4323
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4324
|
+
return p.setExtraDry(methodInput);
|
|
4325
|
+
}),
|
|
4326
|
+
setIntensiveZone: trpc_middleware_js_1.protectedProcedure
|
|
4327
|
+
.input(types_56.dishwasherCapability.methods.setIntensiveZone.input.loose())
|
|
4328
|
+
.output(types_56.dishwasherCapability.methods.setIntensiveZone.output)
|
|
4329
|
+
.mutation(async ({ input, ctx }) => {
|
|
4330
|
+
const { nodeId, ...methodInput } = input;
|
|
4331
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4332
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4333
|
+
return p.setIntensiveZone(methodInput);
|
|
4334
|
+
}),
|
|
4335
|
+
setVarioSpeedPlus: trpc_middleware_js_1.protectedProcedure
|
|
4336
|
+
.input(types_56.dishwasherCapability.methods.setVarioSpeedPlus.input.loose())
|
|
4337
|
+
.output(types_56.dishwasherCapability.methods.setVarioSpeedPlus.output)
|
|
4338
|
+
.mutation(async ({ input, ctx }) => {
|
|
4339
|
+
const { nodeId, ...methodInput } = input;
|
|
4340
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4341
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4342
|
+
return p.setVarioSpeedPlus(methodInput);
|
|
4343
|
+
}),
|
|
4344
|
+
setChildLock: trpc_middleware_js_1.protectedProcedure
|
|
4345
|
+
.input(types_56.dishwasherCapability.methods.setChildLock.input.loose())
|
|
4346
|
+
.output(types_56.dishwasherCapability.methods.setChildLock.output)
|
|
4347
|
+
.mutation(async ({ input, ctx }) => {
|
|
4348
|
+
const { nodeId, ...methodInput } = input;
|
|
4349
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4350
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4351
|
+
return p.setChildLock(methodInput);
|
|
4352
|
+
}),
|
|
4317
4353
|
setOption: trpc_middleware_js_1.protectedProcedure
|
|
4318
4354
|
.input(types_56.dishwasherCapability.methods.setOption.input.loose())
|
|
4319
4355
|
.output(types_56.dishwasherCapability.methods.setOption.output)
|
|
@@ -296,11 +296,20 @@ function buildCapabilityRouters(services) {
|
|
|
296
296
|
// (`import type`) — its value is never called; the codegen
|
|
297
297
|
// `generated-cap-mounts.ts` / `generated-cap-routers.ts` remain the TYPE
|
|
298
298
|
// source of record.
|
|
299
|
+
const integrationRegistry = services.addonRegistry.getIntegrationRegistry();
|
|
300
|
+
const deviceRegistry = services.addonRegistry.getDeviceRegistry();
|
|
299
301
|
const dynamicCaps = (0, cap_router_runtime_js_1.buildRuntimeCapRouters)({
|
|
300
302
|
capabilityRegistry: services.capabilityRegistry,
|
|
301
303
|
moleculer: services.moleculer,
|
|
302
304
|
serverProviders: buildServerProviders(services),
|
|
303
305
|
logger: services.loggingService.createLogger('cap-router'),
|
|
306
|
+
resolveIntegrationAddonId: integrationRegistry
|
|
307
|
+
? async (integrationId) => {
|
|
308
|
+
const row = await integrationRegistry.getIntegration(integrationId);
|
|
309
|
+
return row?.addonId ?? null;
|
|
310
|
+
}
|
|
311
|
+
: undefined,
|
|
312
|
+
resolveDeviceAddonId: (camDeviceId) => deviceRegistry.getAddonId(camDeviceId),
|
|
304
313
|
});
|
|
305
314
|
return {
|
|
306
315
|
// ── Runtime-built cap routers: EVERY cap whose mount is
|
|
@@ -47,6 +47,7 @@ const path = __importStar(require("node:path"));
|
|
|
47
47
|
const system_1 = require("@camstack/system");
|
|
48
48
|
const types_1 = require("@camstack/types");
|
|
49
49
|
const client_1 = require("@trpc/client");
|
|
50
|
+
const hub_addon_api_js_1 = require("./hub-addon-api.js");
|
|
50
51
|
const addon_call_gateway_js_1 = require("./addon-call-gateway.js");
|
|
51
52
|
const addon_row_manifest_1 = require("./addon-row-manifest");
|
|
52
53
|
const addon_settings_provider_js_1 = require("./addon-settings-provider.js");
|
|
@@ -336,29 +337,49 @@ class AddonRegistryService {
|
|
|
336
337
|
*/
|
|
337
338
|
getBrokerApi() {
|
|
338
339
|
if (!this.brokerApi) {
|
|
339
|
-
|
|
340
|
-
const resolver = {
|
|
341
|
-
getByName: (capName) => reg.getSingleton(capName) ?? reg.getAllProviders(capName)[0] ?? null,
|
|
342
|
-
};
|
|
343
|
-
const client = (0, client_1.createTRPCClient)({
|
|
344
|
-
links: [
|
|
345
|
-
(0, system_1.localProviderLink)(resolver),
|
|
346
|
-
// Device-scoped caps go through the hub's CapRouteResolver, which is
|
|
347
|
-
// the only authority that can route `(cap, deviceId)` into a FORKED
|
|
348
|
-
// child — and forked children are broker-less, so the Moleculer
|
|
349
|
-
// lookup below cannot see them at all. Without this an in-process
|
|
350
|
-
// addon asking `ptz.getOptions({deviceId})` got
|
|
351
|
-
// `Service 'ptz.ptz.getOptions' is not found`, which is how the
|
|
352
|
-
// autotrack builtin came up switched on and unable to move a camera
|
|
353
|
-
// (2026-09-18).
|
|
354
|
-
(0, system_1.deviceCapResolverLink)((capName, method, input) => this.moleculer.callCapabilityOnNode(this.moleculer.broker.nodeID, capName, method, input), isDeviceScopedCapName),
|
|
355
|
-
(0, system_1.brokerTransportLink)(this.moleculer.broker),
|
|
356
|
-
],
|
|
357
|
-
});
|
|
358
|
-
this.brokerApi = client;
|
|
340
|
+
this.brokerApi = this.buildBrokerApi(undefined);
|
|
359
341
|
}
|
|
360
342
|
return this.brokerApi;
|
|
361
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* The `ctx.api` of one in-process addon. Same chain as {@link getBrokerApi},
|
|
346
|
+
* but its `localProviderLink` knows WHO is calling, so a caller-stamped cap
|
|
347
|
+
* (`device-history`, keychain, records) can identify the addon. A shared
|
|
348
|
+
* client cannot: `metrics-native` was refused `declareSeries` ("the caller
|
|
349
|
+
* addon could not be identified") on every sample.
|
|
350
|
+
*/
|
|
351
|
+
getAddonApi(addonId) {
|
|
352
|
+
const cached = this.addonApis.get(addonId);
|
|
353
|
+
if (cached)
|
|
354
|
+
return cached;
|
|
355
|
+
const api = this.buildBrokerApi(addonId);
|
|
356
|
+
this.addonApis.set(addonId, api);
|
|
357
|
+
return api;
|
|
358
|
+
}
|
|
359
|
+
addonApis = new Map();
|
|
360
|
+
buildBrokerApi(callerAddonId) {
|
|
361
|
+
const reg = this.capabilityRegistry;
|
|
362
|
+
const resolver = {
|
|
363
|
+
getByName: (capName) => reg.getSingleton(capName) ?? reg.getAllProviders(capName)[0] ?? null,
|
|
364
|
+
};
|
|
365
|
+
// Device-scoped caps go through the hub's CapRouteResolver, which is
|
|
366
|
+
// the only authority that can route `(cap, deviceId)` into a FORKED
|
|
367
|
+
// child — and forked children are broker-less, so the Moleculer
|
|
368
|
+
// lookup below cannot see them at all. Without this an in-process
|
|
369
|
+
// addon asking `ptz.getOptions({deviceId})` got
|
|
370
|
+
// `Service 'ptz.ptz.getOptions' is not found`, which is how the
|
|
371
|
+
// autotrack builtin came up switched on and unable to move a camera
|
|
372
|
+
// (2026-09-18).
|
|
373
|
+
const links = [
|
|
374
|
+
(0, system_1.deviceCapResolverLink)((capName, method, input) => this.moleculer.callCapabilityOnNode(this.moleculer.broker.nodeID, capName, method, input), isDeviceScopedCapName),
|
|
375
|
+
(0, system_1.brokerTransportLink)(this.moleculer.broker),
|
|
376
|
+
];
|
|
377
|
+
if (callerAddonId !== undefined) {
|
|
378
|
+
return (0, hub_addon_api_js_1.createHubAddonApi)({ resolver, callerAddonId, links });
|
|
379
|
+
}
|
|
380
|
+
const client = (0, client_1.createTRPCClient)({ links: [(0, system_1.localProviderLink)(resolver), ...links] });
|
|
381
|
+
return client;
|
|
382
|
+
}
|
|
362
383
|
// Common settings resolver (3-level: defaults → global → per-device).
|
|
363
384
|
// Lazily constructed on first call to `getSettingsResolver()` so tests
|
|
364
385
|
// that don't exercise the settings API can instantiate the service
|
|
@@ -3013,7 +3034,7 @@ class AddonRegistryService {
|
|
|
3013
3034
|
dataPlane: dataPlaneFacility.dataPlane,
|
|
3014
3035
|
peerBytes: peerBytesFacility.peerBytes,
|
|
3015
3036
|
get api() {
|
|
3016
|
-
return registry.
|
|
3037
|
+
return registry.getAddonApi(addonId);
|
|
3017
3038
|
},
|
|
3018
3039
|
integrationRegistry: this.integrationRegistry ?? undefined,
|
|
3019
3040
|
// Live capability-collection accessor used by addons like stream-broker
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The `ctx.api` of an in-process hub addon.
|
|
4
|
+
*
|
|
5
|
+
* Identity is the whole point: a caller-stamped capability (`device-history`,
|
|
6
|
+
* keychain, records) learns WHO is calling only from the `callerAddonId` its
|
|
7
|
+
* `localProviderLink` stamps, so each addon needs its own client — a shared one
|
|
8
|
+
* cannot say whose call it is.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createHubAddonApi = createHubAddonApi;
|
|
12
|
+
const client_1 = require("@trpc/client");
|
|
13
|
+
const system_1 = require("@camstack/system");
|
|
14
|
+
function createHubAddonApi(options) {
|
|
15
|
+
// The observer options carry the stamp only. Cap usage stays recorded on the
|
|
16
|
+
// callee side (`LocalChildRegistry`), so in-process calls are not counted
|
|
17
|
+
// here and the hub's usage graph keeps its meaning.
|
|
18
|
+
const observerOpts = {
|
|
19
|
+
callerAddonId: options.callerAddonId,
|
|
20
|
+
providerAddonIdForCap: () => null,
|
|
21
|
+
observer: () => undefined,
|
|
22
|
+
};
|
|
23
|
+
const client = (0, client_1.createTRPCClient)({
|
|
24
|
+
links: [(0, system_1.localProviderLink)(options.resolver, observerOpts), ...options.links],
|
|
25
|
+
});
|
|
26
|
+
return client;
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.602",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"files": [
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
]
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@camstack/addon-admin-ui": "1.2.
|
|
42
|
-
"@camstack/addon-agent-ui": "1.2.
|
|
43
|
-
"@camstack/addon-auth": "1.2.
|
|
44
|
-
"@camstack/addon-decoder-nodeav": "1.2.
|
|
45
|
-
"@camstack/addon-notifiers": "1.2.
|
|
46
|
-
"@camstack/addon-pipeline": "1.2.
|
|
47
|
-
"@camstack/addon-pipeline-orchestrator": "1.2.
|
|
48
|
-
"@camstack/addon-post-analysis": "1.2.
|
|
49
|
-
"@camstack/develop": "0.1.
|
|
50
|
-
"@camstack/sdk": "1.2.
|
|
51
|
-
"@camstack/system": "1.2.
|
|
52
|
-
"@camstack/types": "1.2.
|
|
53
|
-
"@camstack/ui-library": "1.2.
|
|
41
|
+
"@camstack/addon-admin-ui": "1.2.439",
|
|
42
|
+
"@camstack/addon-agent-ui": "1.2.245",
|
|
43
|
+
"@camstack/addon-auth": "1.2.150",
|
|
44
|
+
"@camstack/addon-decoder-nodeav": "1.2.124",
|
|
45
|
+
"@camstack/addon-notifiers": "1.2.602",
|
|
46
|
+
"@camstack/addon-pipeline": "1.2.602",
|
|
47
|
+
"@camstack/addon-pipeline-orchestrator": "1.2.603",
|
|
48
|
+
"@camstack/addon-post-analysis": "1.2.607",
|
|
49
|
+
"@camstack/develop": "0.1.14",
|
|
50
|
+
"@camstack/sdk": "1.2.134",
|
|
51
|
+
"@camstack/system": "1.2.453",
|
|
52
|
+
"@camstack/types": "1.2.384",
|
|
53
|
+
"@camstack/ui-library": "1.2.301",
|
|
54
54
|
"@fastify/compress": "^9.0.0",
|
|
55
55
|
"@fastify/cookie": "^11.0.2",
|
|
56
56
|
"@fastify/cors": "^11.2.0",
|