@camstack/core 0.1.38 → 0.1.39

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 (52) hide show
  1. package/dist/auth/auth-manager.d.ts +12 -1
  2. package/dist/auth/auth-manager.d.ts.map +1 -1
  3. package/dist/auth/scope-matcher.d.ts +8 -0
  4. package/dist/auth/scope-matcher.d.ts.map +1 -0
  5. package/dist/auth/totp-manager.d.ts +0 -1
  6. package/dist/auth/totp-manager.d.ts.map +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +15 -0
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts.map +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +27 -6
  10. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -1
  11. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +27 -6
  12. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -1
  13. package/dist/builtins/device-manager/device-config-contribution.d.ts +33 -0
  14. package/dist/builtins/device-manager/device-config-contribution.d.ts.map +1 -0
  15. package/dist/builtins/device-manager/device-manager.addon.d.ts +52 -17
  16. package/dist/builtins/device-manager/device-manager.addon.d.ts.map +1 -1
  17. package/dist/builtins/device-manager/device-manager.addon.js +285 -161
  18. package/dist/builtins/device-manager/device-manager.addon.js.map +1 -1
  19. package/dist/builtins/device-manager/device-manager.addon.mjs +286 -162
  20. package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -1
  21. package/dist/builtins/local-auth/auth-schema.d.ts +1 -0
  22. package/dist/builtins/local-auth/auth-schema.d.ts.map +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.d.ts +1 -0
  24. package/dist/builtins/local-auth/local-auth.addon.d.ts.map +1 -1
  25. package/dist/builtins/local-auth/local-auth.addon.js +354 -3
  26. package/dist/builtins/local-auth/local-auth.addon.js.map +1 -1
  27. package/dist/builtins/local-auth/local-auth.addon.mjs +355 -3
  28. package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -1
  29. package/dist/builtins/local-auth/oauth-grants.d.ts +46 -0
  30. package/dist/builtins/local-auth/oauth-grants.d.ts.map +1 -0
  31. package/dist/builtins/local-auth/oauth-session-manager.d.ts +51 -0
  32. package/dist/builtins/local-auth/oauth-session-manager.d.ts.map +1 -0
  33. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +97 -0
  34. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts.map +1 -0
  35. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +17 -0
  36. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +95 -5
  38. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -1
  39. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +95 -5
  40. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -1
  41. package/dist/builtins/snapshot/index.js +1 -3
  42. package/dist/builtins/snapshot/index.js.map +1 -1
  43. package/dist/builtins/snapshot/index.mjs +1 -3
  44. package/dist/builtins/snapshot/index.mjs.map +1 -1
  45. package/dist/builtins/snapshot/snapshot.addon.d.ts.map +1 -1
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +419 -97
  49. package/dist/index.js.map +1 -1
  50. package/dist/index.mjs +419 -98
  51. package/dist/index.mjs.map +1 -1
  52. package/package.json +19 -1
package/dist/index.mjs CHANGED
@@ -31,7 +31,7 @@ import { promisify } from "node:util";
31
31
  import { errMsg, parseJsonObject } from "@camstack/types";
32
32
  import * as vm from "node:vm";
33
33
  import * as os from "node:os";
34
- //#region ../types/dist/index-CWhQOnm9.mjs
34
+ //#region ../types/dist/index-CgPd35k5.mjs
35
35
  var MODEL_FORMATS = [
36
36
  "onnx",
37
37
  "coreml",
@@ -106,6 +106,12 @@ Object.fromEntries([
106
106
  icon: "video",
107
107
  order: 35
108
108
  },
109
+ {
110
+ id: "ptz",
111
+ label: "PTZ",
112
+ icon: "move",
113
+ order: 40
114
+ },
109
115
  {
110
116
  id: "pipeline",
111
117
  label: "Detection Pipeline",
@@ -232,7 +238,19 @@ var DecoderSessionConfigSchema = z.object({
232
238
  * on every line so `grep tag=broker:5/high` filters one camera
233
239
  * profile cleanly.
234
240
  */
235
- tag: z.string().optional()
241
+ tag: z.string().optional(),
242
+ /**
243
+ * Where the session delivers decoded frames (Phase 5 / D9):
244
+ *
245
+ * - `'callback'` (default) — the legacy pixel path: decoded frames are
246
+ * buffered as `DecodedFrame`s and drained via `pullFrames`.
247
+ * - `'shm'` — the shared-memory frame plane: decoded frames are written
248
+ * into an OS shared-memory ring and drained as zero-pixel
249
+ * `FrameHandle`s via `pullHandles`. A session is one mode or the
250
+ * other — `pullFrames` returns nothing for an `'shm'` session and
251
+ * `pullHandles` returns nothing for a `'callback'` session.
252
+ */
253
+ frameSink: z.enum(["callback", "shm"]).default("callback")
236
254
  });
237
255
  function errMsg$1(err) {
238
256
  if (err instanceof Error) return err.message;
@@ -892,6 +910,63 @@ var DecodedFrameSchema = z.object({
892
910
  ]),
893
911
  timestamp: z.number()
894
912
  });
913
+ var FrameHandleSchema = z.object({
914
+ shmId: z.string(),
915
+ slot: z.number().int().nonnegative(),
916
+ seq: z.number().int().nonnegative(),
917
+ width: z.number().int().positive(),
918
+ height: z.number().int().positive(),
919
+ format: z.enum([
920
+ "jpeg",
921
+ "rgb",
922
+ "bgr",
923
+ "yuv420",
924
+ "gray"
925
+ ]),
926
+ pts: z.number(),
927
+ byteLength: z.number().int().nonnegative(),
928
+ nodeId: z.string(),
929
+ slotCount: z.number().int().positive()
930
+ });
931
+ var FrameHandleFormatSchema = z.enum([
932
+ "rgb",
933
+ "bgr",
934
+ "yuv420",
935
+ "gray"
936
+ ]);
937
+ var SubscribeFramesInputSchema = z.object({
938
+ brokerId: z.string(),
939
+ format: FrameHandleFormatSchema,
940
+ /**
941
+ * Optional reader-side cadence hint in frames per second. The broker does
942
+ * NOT throttle — latest-wins ring reads drop frames implicitly for a slow
943
+ * consumer. The value is echoed back in `SubscribeFramesResult.maxFps` so
944
+ * the consumer can pace its own `pullFrameHandles` polling.
945
+ */
946
+ maxFps: z.number().positive().optional(),
947
+ /** Short caller-identity tag (`motion`, `detection`, …) for diagnostics. */
948
+ tag: z.string().optional()
949
+ });
950
+ var SubscribeFramesResultSchema = z.object({
951
+ /** Opaque id the consumer passes to `pullFrameHandles` / `unsubscribeFrames`. */
952
+ subscriptionId: z.string(),
953
+ /** Reader-side cadence hint (frames/s) — echoes `SubscribeFramesInput.maxFps`. */
954
+ maxFps: z.number().nonnegative()
955
+ });
956
+ var DecodedAudioChunkSchema = z.object({
957
+ data: z.instanceof(Uint8Array),
958
+ sampleRate: z.number().int().positive(),
959
+ channels: z.number().int().positive(),
960
+ timestamp: z.number()
961
+ });
962
+ var SubscribeAudioChunksInputSchema = z.object({
963
+ brokerId: z.string(),
964
+ /** Short caller-identity tag (`audio-analyzer`, …) for `listClients`. */
965
+ tag: z.string().optional()
966
+ });
967
+ var SubscribeAudioChunksResultSchema = z.object({
968
+ /** Opaque id passed to `pullAudioChunks` / `unsubscribeAudioChunks`. */
969
+ subscriptionId: z.string() });
895
970
  var BrokerStatusSchema$1 = z.enum([
896
971
  "idle",
897
972
  "connecting",
@@ -1094,7 +1169,13 @@ method(z.object({
1094
1169
  }), {
1095
1170
  kind: "mutation",
1096
1171
  auth: "admin"
1097
- }), method(z.object({ brokerId: z.string() }), z.custom()), method(z.object({
1172
+ }), method(SubscribeAudioChunksInputSchema, SubscribeAudioChunksResultSchema, { kind: "mutation" }), method(z.object({
1173
+ subscriptionId: z.string(),
1174
+ maxCount: z.number().int().positive().default(8)
1175
+ }), z.array(DecodedAudioChunkSchema).readonly()), method(z.object({ subscriptionId: z.string() }), z.object({ released: z.boolean() }), { kind: "mutation" }), method(SubscribeFramesInputSchema, SubscribeFramesResultSchema, { kind: "mutation" }), method(z.object({
1176
+ subscriptionId: z.string(),
1177
+ maxCount: z.number().int().positive().default(4)
1178
+ }), z.array(FrameHandleSchema).readonly()), method(z.object({ subscriptionId: z.string() }), z.object({ released: z.boolean() }), { kind: "mutation" }), method(z.object({
1098
1179
  brokerId: z.string(),
1099
1180
  seconds: z.number().min(0).max(30)
1100
1181
  }), z.void(), {
@@ -1787,6 +1868,34 @@ DeviceType$1.Light, DeviceType$1.Siren, DeviceType$1.Switch, method(z.object({
1787
1868
  enabled: z.boolean(),
1788
1869
  lastChangedAt: z.number()
1789
1870
  });
1871
+ z.object({
1872
+ enabled: z.boolean(),
1873
+ sensitivity: z.number(),
1874
+ /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
1875
+ cells: z.array(z.boolean()),
1876
+ lastFetchedAt: z.number()
1877
+ });
1878
+ var MotionZoneOptionsSchema = z.object({
1879
+ gridWidth: z.number(),
1880
+ gridHeight: z.number(),
1881
+ sensitivity: z.object({
1882
+ min: z.number(),
1883
+ max: z.number(),
1884
+ step: z.number()
1885
+ })
1886
+ });
1887
+ var MotionZonePatchSchema = z.object({
1888
+ enabled: z.boolean().optional(),
1889
+ sensitivity: z.number().optional(),
1890
+ cells: z.array(z.boolean()).optional()
1891
+ });
1892
+ DeviceType$1.Camera, method(z.object({ deviceId: z.number() }), MotionZoneOptionsSchema), method(z.object({
1893
+ deviceId: z.number(),
1894
+ patch: MotionZonePatchSchema
1895
+ }), z.void(), {
1896
+ kind: "mutation",
1897
+ auth: "admin"
1898
+ });
1790
1899
  var AutotrackTargetTypeSchema = z.string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
1791
1900
  var PtzAutotrackSettingsSchema = z.object({
1792
1901
  targetType: AutotrackTargetTypeSchema,
@@ -1829,6 +1938,85 @@ DeviceType$1.Camera, method(z.object({ deviceId: z.number() }), PtzAutotrackStat
1829
1938
  deviceId: z.number(),
1830
1939
  status: PtzAutotrackStatusSchema
1831
1940
  });
1941
+ var StreamProfileSchema = z.enum([
1942
+ "main",
1943
+ "sub",
1944
+ "ext"
1945
+ ]);
1946
+ var StreamProfileConfigSchema = z.object({
1947
+ width: z.number(),
1948
+ height: z.number(),
1949
+ codec: z.enum(["h264", "h265"]),
1950
+ framerate: z.number(),
1951
+ bitrate: z.number(),
1952
+ bitrateMode: z.enum(["vbr", "cbr"]).optional(),
1953
+ encoderProfile: z.enum([
1954
+ "high",
1955
+ "main",
1956
+ "baseline"
1957
+ ]).optional(),
1958
+ gop: z.number().optional(),
1959
+ audio: z.boolean().optional()
1960
+ });
1961
+ z.object({
1962
+ /** Per-profile current config. A profile absent = the camera doesn't have it. */
1963
+ main: StreamProfileConfigSchema.optional(),
1964
+ sub: StreamProfileConfigSchema.optional(),
1965
+ ext: StreamProfileConfigSchema.optional(),
1966
+ lastFetchedAt: z.number()
1967
+ });
1968
+ var StreamProfileOptionsSchema = z.object({
1969
+ resolutions: z.array(z.object({
1970
+ width: z.number(),
1971
+ height: z.number()
1972
+ })),
1973
+ codecs: z.array(z.enum(["h264", "h265"])),
1974
+ framerates: z.array(z.number()),
1975
+ /** Allowed bitrate values (kbps). Empty if the camera takes a free range. */
1976
+ bitrates: z.array(z.number()),
1977
+ /** Optional [min,max] kbps when the camera accepts a continuous range. */
1978
+ bitrateRange: z.tuple([z.number(), z.number()]).optional(),
1979
+ supportsBitrateMode: z.boolean(),
1980
+ supportsEncoderProfile: z.boolean(),
1981
+ supportsGop: z.boolean(),
1982
+ /** Allowed GOP / keyframe-interval range, in seconds — drives the
1983
+ * I-frame-interval selector. Absent when the camera advertises GOP
1984
+ * support but no concrete range (callers then fall back to a free
1985
+ * numeric input). `{ min, max, step }` per the getOptions convention. */
1986
+ gop: z.object({
1987
+ min: z.number(),
1988
+ max: z.number(),
1989
+ step: z.number()
1990
+ }).optional()
1991
+ });
1992
+ var StreamParamsOptionsSchema = z.object({
1993
+ main: StreamProfileOptionsSchema.optional(),
1994
+ sub: StreamProfileOptionsSchema.optional(),
1995
+ ext: StreamProfileOptionsSchema.optional()
1996
+ });
1997
+ var StreamProfilePatchSchema = z.object({
1998
+ width: z.number().optional(),
1999
+ height: z.number().optional(),
2000
+ codec: z.enum(["h264", "h265"]).optional(),
2001
+ framerate: z.number().optional(),
2002
+ bitrate: z.number().optional(),
2003
+ bitrateMode: z.enum(["vbr", "cbr"]).optional(),
2004
+ encoderProfile: z.enum([
2005
+ "high",
2006
+ "main",
2007
+ "baseline"
2008
+ ]).optional(),
2009
+ gop: z.number().optional(),
2010
+ audio: z.boolean().optional()
2011
+ });
2012
+ DeviceType$1.Camera, method(z.object({ deviceId: z.number() }), StreamParamsOptionsSchema), method(z.object({
2013
+ deviceId: z.number(),
2014
+ profile: StreamProfileSchema,
2015
+ patch: StreamProfilePatchSchema
2016
+ }), z.void(), {
2017
+ kind: "mutation",
2018
+ auth: "admin"
2019
+ }), method(z.object({ deviceId: z.number() }), z.unknown().nullable());
1832
2020
  z.object({
1833
2021
  on: z.boolean(),
1834
2022
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
@@ -2468,6 +2656,85 @@ method(LogEntrySchema, z.void(), { kind: "mutation" }), method(z.object({
2468
2656
  var StaticDirOutputSchema = z.object({ staticDir: z.string() });
2469
2657
  var VersionOutputSchema = z.object({ version: z.string() });
2470
2658
  method(z.void(), StaticDirOutputSchema), method(z.void(), VersionOutputSchema);
2659
+ var MethodAccessSchema = z.enum([
2660
+ "view",
2661
+ "create",
2662
+ "delete"
2663
+ ]);
2664
+ var AllowedProviderSchema = z.union([z.literal("*"), z.array(z.string())]);
2665
+ var AllowedDevicesSchema = z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]));
2666
+ var CapScopeSchema = z.enum(["device", "system"]);
2667
+ var TokenScopeSchema = z.discriminatedUnion("type", [
2668
+ z.object({
2669
+ type: z.literal("category"),
2670
+ target: CapScopeSchema,
2671
+ access: z.array(MethodAccessSchema).min(1)
2672
+ }),
2673
+ z.object({
2674
+ type: z.literal("capability"),
2675
+ target: z.string(),
2676
+ access: z.array(MethodAccessSchema).min(1)
2677
+ }),
2678
+ z.object({
2679
+ type: z.literal("addon"),
2680
+ target: z.string(),
2681
+ access: z.array(MethodAccessSchema).min(1)
2682
+ }),
2683
+ z.object({
2684
+ type: z.literal("device"),
2685
+ /**
2686
+ * One or more deviceIds (serialised as strings for wire-format
2687
+ * consistency with the rest of the union). Matcher accepts if
2688
+ * `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
2689
+ * of one scope-per-device when granting access to a set of cameras.
2690
+ */
2691
+ targets: z.array(z.string()).min(1),
2692
+ access: z.array(MethodAccessSchema).min(1)
2693
+ })
2694
+ ]);
2695
+ z.object({
2696
+ id: z.string(),
2697
+ username: z.string(),
2698
+ passwordHash: z.string(),
2699
+ /**
2700
+ * Admin bypass. When true, the middleware skips the scope-access
2701
+ * check entirely. There is no other axis of privilege; the legacy
2702
+ * role enum collapsed onto this boolean in v2.
2703
+ */
2704
+ isAdmin: z.boolean().default(false),
2705
+ allowedProviders: AllowedProviderSchema,
2706
+ allowedDevices: AllowedDevicesSchema,
2707
+ /**
2708
+ * Scopes granted to this user. Admins bypass; their `scopes` is
2709
+ * ignored. Non-admins without scopes are locked out of every
2710
+ * protected call.
2711
+ */
2712
+ scopes: z.array(TokenScopeSchema).default([]),
2713
+ createdAt: z.number(),
2714
+ updatedAt: z.number()
2715
+ });
2716
+ z.object({
2717
+ id: z.string(),
2718
+ label: z.string(),
2719
+ isAdmin: z.boolean().default(false),
2720
+ allowedProviders: AllowedProviderSchema,
2721
+ allowedDevices: AllowedDevicesSchema,
2722
+ tokenHash: z.string(),
2723
+ tokenPrefix: z.string(),
2724
+ createdAt: z.number(),
2725
+ lastUsedAt: z.number().optional()
2726
+ });
2727
+ z.object({
2728
+ id: z.string(),
2729
+ userId: z.string(),
2730
+ name: z.string(),
2731
+ tokenHash: z.string(),
2732
+ tokenPrefix: z.string(),
2733
+ scopes: z.array(TokenScopeSchema),
2734
+ expiresAt: z.number().nullish(),
2735
+ lastUsedAt: z.number().nullish(),
2736
+ createdAt: z.number()
2737
+ });
2471
2738
  var SsoBridgeClaimsSchema = z.object({
2472
2739
  userId: z.string(),
2473
2740
  username: z.string(),
@@ -2483,12 +2750,36 @@ var SsoBridgeClaimsSchema = z.object({
2483
2750
  * JWT WITHOUT verifying the signature — the hub re-verifies on every
2484
2751
  * inbound call so trust still rests with the signing hub.
2485
2752
  */
2486
- hubUrl: z.string().optional()
2753
+ hubUrl: z.string().optional(),
2754
+ /** Permission scopes baked into the token. Set by the OAuth
2755
+ * account-linking grant; absent on ordinary SSO-login tokens. */
2756
+ scopes: z.array(TokenScopeSchema).optional(),
2757
+ /** OAuth authorization-code binding — set only on `oauth-code` tokens. */
2758
+ redirectUri: z.string().optional(),
2759
+ integrationId: z.string().optional(),
2760
+ /** JWT ID — unique per issued code; consumed-set enforces single-use. */
2761
+ jti: z.string().optional(),
2762
+ /** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
2763
+ * tokens so the verify path can check the session is not revoked. */
2764
+ sessionId: z.string().optional()
2487
2765
  });
2488
2766
  method(z.object({
2489
2767
  claims: SsoBridgeClaimsSchema,
2490
2768
  ttlSec: z.number().int().positive().optional()
2491
2769
  }), z.object({ token: z.string() })), method(z.object({ token: z.string() }), SsoBridgeClaimsSchema.nullable());
2770
+ var OauthIntegrationDescriptorSchema = z.object({
2771
+ /** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
2772
+ integrationId: z.string(),
2773
+ /** Human label rendered on the consent page. */
2774
+ displayName: z.string(),
2775
+ /** Scopes baked into every token issued for this integration. */
2776
+ requestedScopes: z.array(TokenScopeSchema),
2777
+ /** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
2778
+ * redirect_uri that does not start with one of these. Required —
2779
+ * an empty list means the integration can never complete linking. */
2780
+ allowedRedirectPrefixes: z.array(z.string()).min(1)
2781
+ });
2782
+ method(z.void(), OauthIntegrationDescriptorSchema);
2492
2783
  var PasskeySummarySchema = z.object({
2493
2784
  credentialId: z.string(),
2494
2785
  label: z.string(),
@@ -2734,22 +3025,29 @@ var WidgetSizeEnum = z.enum([
2734
3025
  "lg",
2735
3026
  "xl"
2736
3027
  ]);
3028
+ var WidgetRemoteSchema = z.object({
3029
+ remoteName: z.string(),
3030
+ exposedModule: z.string(),
3031
+ componentKey: z.string().optional()
3032
+ });
2737
3033
  var WidgetMetadataSchema = z.object({
2738
- /** Stable id within the addon kebab-case. */
2739
- stableId: z.string(),
3034
+ /** Primary host tab `'dashboard'`, `'device-tab'`, or a device-detail tab id. */
3035
+ tab: z.string(),
3036
+ /** Optional sub-tab within `tab`. */
3037
+ subTab: z.string().optional(),
2740
3038
  /** Operator-facing label. */
2741
3039
  label: z.string(),
3040
+ /** Ordering within `(tab, subTab)`, ascending. */
3041
+ order: z.number().optional(),
3042
+ /** Always `'remote'` — a widget is a Module Federation remote. */
3043
+ kind: z.literal("remote"),
3044
+ /** MF remote descriptor. */
3045
+ remote: WidgetRemoteSchema,
3046
+ /** Stable id within the addon — kebab-case. Equals `remote.componentKey`. */
3047
+ stableId: z.string(),
2742
3048
  description: z.string().optional(),
2743
3049
  icon: z.string().optional(),
2744
3050
  /**
2745
- * Module Federation remote name — must match the `name` field on the
2746
- * widget addon's `federation()` plugin config. Used by the host's
2747
- * `<WidgetRegistryProvider>` to call `loadRemote('<remoteName>/widgets')`.
2748
- * Conventionally `addon_<addonid>_widgets` (snake_case; MF names
2749
- * cannot contain hyphens).
2750
- */
2751
- remoteName: z.string(),
2752
- /**
2753
3051
  * Bundle filename inside the addon's `dist/` dir served at
2754
3052
  * `/api/addon-widgets/<addonId>/<bundle>`. With Module Federation
2755
3053
  * this is always `'remoteEntry.js'` — the value is kept on the
@@ -2757,9 +3055,9 @@ var WidgetMetadataSchema = z.object({
2757
3055
  * cache-buster URL without a separate filesystem stat.
2758
3056
  */
2759
3057
  bundle: z.string(),
2760
- /** Where the widget makes sense to render. */
3058
+ /** Every host the widget supports. The picker filters on this set. */
2761
3059
  hosts: z.array(WidgetHostEnum).readonly(),
2762
- /** Required props the host must supply. Validated at <WidgetSlot> mount. */
3060
+ /** Required props the host must supply. Validated at `<WidgetSlot>` mount. */
2763
3061
  requires: z.object({
2764
3062
  deviceContext: z.boolean().default(false),
2765
3063
  integrationContext: z.boolean().default(false)
@@ -2823,6 +3121,16 @@ var InvokeReplyEnvelopeSchema = z.object({
2823
3121
  contentType: z.string().optional()
2824
3122
  });
2825
3123
  method(z.void(), z.array(AddonHttpRouteSchema)), method(InvokeRequestSchema, InvokeReplyEnvelopeSchema, { kind: "mutation" });
3124
+ var ShmRingStatsSchema = z.object({
3125
+ sessionId: z.string(),
3126
+ slotCount: z.number().int(),
3127
+ slotByteLength: z.number().int(),
3128
+ segmentBytes: z.number().int(),
3129
+ budgetMb: z.number().int(),
3130
+ framesWritten: z.number().int(),
3131
+ getFrameHits: z.number().int(),
3132
+ getFrameMisses: z.number().int()
3133
+ });
2826
3134
  method(z.object({ codec: z.string() }), z.boolean()), method(z.void(), z.object({
2827
3135
  id: z.string(),
2828
3136
  name: z.string(),
@@ -2841,6 +3149,9 @@ method(z.object({ codec: z.string() }), z.boolean()), method(z.void(), z.object(
2841
3149
  sessionId: z.string(),
2842
3150
  maxCount: z.number().default(1)
2843
3151
  }), z.array(DecodedFrameSchema)), method(z.object({
3152
+ sessionId: z.string(),
3153
+ maxCount: z.number().default(1)
3154
+ }), z.array(FrameHandleSchema)), method(z.object({ handle: FrameHandleSchema }), DecodedFrameSchema.nullable()), method(z.object({ sessionId: z.string() }), ShmRingStatsSchema.nullable()), method(z.object({
2844
3155
  sessionId: z.string(),
2845
3156
  config: DecoderSessionConfigSchema.partial()
2846
3157
  }), z.void()), method(z.object({ sessionId: z.string() }), DecoderStatsSchema), method(z.void(), z.array(z.object({
@@ -4219,10 +4530,38 @@ var PtzMoveCommandSchema = z.object({
4219
4530
  zoom: z.number().optional(),
4220
4531
  speed: z.number().optional()
4221
4532
  });
4533
+ PtzPositionSchema.extend({ autofocus: z.boolean() });
4534
+ var PtzOptionsSchema = z.object({
4535
+ hasPan: z.boolean(),
4536
+ hasTilt: z.boolean(),
4537
+ hasZoom: z.boolean(),
4538
+ supportsPresets: z.boolean(),
4539
+ /** Max number of named presets the camera supports, when known. */
4540
+ maxPresets: z.number().optional(),
4541
+ /** Whether the camera exposes a controllable autofocus toggle
4542
+ * (boolean `hasX` per the getOptions availability convention). */
4543
+ hasAutofocus: z.boolean()
4544
+ });
4222
4545
  DeviceType$1.Camera, method(PtzMoveCommandSchema.extend({ deviceId: z.number() }), z.void(), { kind: "mutation" }), method(PtzMoveCommandSchema.extend({ deviceId: z.number() }), z.void(), { kind: "mutation" }), method(z.object({ deviceId: z.number() }), z.void(), { kind: "mutation" }), method(z.object({ deviceId: z.number() }), z.array(PtzPresetSchema)), method(z.object({
4223
4546
  deviceId: z.number(),
4224
4547
  presetId: z.string()
4225
- }), z.void(), { kind: "mutation" }), method(z.object({ deviceId: z.number() }), z.void(), { kind: "mutation" }), method(z.object({ deviceId: z.number() }), PtzPositionSchema);
4548
+ }), z.void(), { kind: "mutation" }), method(z.object({
4549
+ deviceId: z.number(),
4550
+ presetId: z.string(),
4551
+ name: z.string()
4552
+ }), z.void(), {
4553
+ kind: "mutation",
4554
+ auth: "admin"
4555
+ }), method(z.object({
4556
+ deviceId: z.number(),
4557
+ presetId: z.string()
4558
+ }), z.void(), {
4559
+ kind: "mutation",
4560
+ auth: "admin"
4561
+ }), method(z.object({ deviceId: z.number() }), PtzOptionsSchema), method(z.object({ deviceId: z.number() }), z.void(), { kind: "mutation" }), method(z.object({ deviceId: z.number() }), PtzPositionSchema), method(z.object({
4562
+ deviceId: z.number(),
4563
+ enabled: z.boolean()
4564
+ }), z.void(), { kind: "mutation" });
4226
4565
  var EventItemSchema = z.object({
4227
4566
  id: z.string(),
4228
4567
  type: z.string(),
@@ -4865,85 +5204,6 @@ authKey: z.string().optional() }), z.object({
4865
5204
  /** Human-readable error when `ok: false`. */
4866
5205
  error: z.string().optional()
4867
5206
  }), { kind: "mutation" });
4868
- var MethodAccessSchema = z.enum([
4869
- "view",
4870
- "create",
4871
- "delete"
4872
- ]);
4873
- var AllowedProviderSchema = z.union([z.literal("*"), z.array(z.string())]);
4874
- var AllowedDevicesSchema = z.record(z.string(), z.union([z.literal("*"), z.array(z.string())]));
4875
- var CapScopeSchema = z.enum(["device", "system"]);
4876
- var TokenScopeSchema = z.discriminatedUnion("type", [
4877
- z.object({
4878
- type: z.literal("category"),
4879
- target: CapScopeSchema,
4880
- access: z.array(MethodAccessSchema).min(1)
4881
- }),
4882
- z.object({
4883
- type: z.literal("capability"),
4884
- target: z.string(),
4885
- access: z.array(MethodAccessSchema).min(1)
4886
- }),
4887
- z.object({
4888
- type: z.literal("addon"),
4889
- target: z.string(),
4890
- access: z.array(MethodAccessSchema).min(1)
4891
- }),
4892
- z.object({
4893
- type: z.literal("device"),
4894
- /**
4895
- * One or more deviceIds (serialised as strings for wire-format
4896
- * consistency with the rest of the union). Matcher accepts if
4897
- * `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
4898
- * of one scope-per-device when granting access to a set of cameras.
4899
- */
4900
- targets: z.array(z.string()).min(1),
4901
- access: z.array(MethodAccessSchema).min(1)
4902
- })
4903
- ]);
4904
- z.object({
4905
- id: z.string(),
4906
- username: z.string(),
4907
- passwordHash: z.string(),
4908
- /**
4909
- * Admin bypass. When true, the middleware skips the scope-access
4910
- * check entirely. There is no other axis of privilege; the legacy
4911
- * role enum collapsed onto this boolean in v2.
4912
- */
4913
- isAdmin: z.boolean().default(false),
4914
- allowedProviders: AllowedProviderSchema,
4915
- allowedDevices: AllowedDevicesSchema,
4916
- /**
4917
- * Scopes granted to this user. Admins bypass; their `scopes` is
4918
- * ignored. Non-admins without scopes are locked out of every
4919
- * protected call.
4920
- */
4921
- scopes: z.array(TokenScopeSchema).default([]),
4922
- createdAt: z.number(),
4923
- updatedAt: z.number()
4924
- });
4925
- z.object({
4926
- id: z.string(),
4927
- label: z.string(),
4928
- isAdmin: z.boolean().default(false),
4929
- allowedProviders: AllowedProviderSchema,
4930
- allowedDevices: AllowedDevicesSchema,
4931
- tokenHash: z.string(),
4932
- tokenPrefix: z.string(),
4933
- createdAt: z.number(),
4934
- lastUsedAt: z.number().optional()
4935
- });
4936
- z.object({
4937
- id: z.string(),
4938
- userId: z.string(),
4939
- name: z.string(),
4940
- tokenHash: z.string(),
4941
- tokenPrefix: z.string(),
4942
- scopes: z.array(TokenScopeSchema),
4943
- expiresAt: z.number().nullish(),
4944
- lastUsedAt: z.number().nullish(),
4945
- createdAt: z.number()
4946
- });
4947
5207
  var UserSummarySchema = z.object({
4948
5208
  id: z.string(),
4949
5209
  username: z.string(),
@@ -5016,6 +5276,16 @@ var CreateScopedTokenResultSchema = z.object({
5016
5276
  token: z.string(),
5017
5277
  record: ScopedTokenSummarySchema
5018
5278
  });
5279
+ var OauthSessionSummarySchema = z.object({
5280
+ id: z.string(),
5281
+ userId: z.string(),
5282
+ username: z.string(),
5283
+ integrationId: z.string(),
5284
+ scopes: z.array(TokenScopeSchema),
5285
+ createdAt: z.number(),
5286
+ lastUsedAt: z.number(),
5287
+ revokedAt: z.number().nullable()
5288
+ });
5019
5289
  var TotpSetupResultSchema = z.object({
5020
5290
  secret: z.string(),
5021
5291
  otpauthUrl: z.string()
@@ -5098,6 +5368,41 @@ method(z.void(), z.array(UserSummarySchema), { auth: "admin" }), method(CreateUs
5098
5368
  }), z.object({ valid: z.boolean() }), {
5099
5369
  kind: "mutation",
5100
5370
  access: "view"
5371
+ }), method(z.object({
5372
+ integrationId: z.string(),
5373
+ userId: z.string(),
5374
+ username: z.string(),
5375
+ scopes: z.array(TokenScopeSchema),
5376
+ redirectUri: z.string(),
5377
+ hubUrl: z.string()
5378
+ }), z.object({ code: z.string() }), {
5379
+ kind: "mutation",
5380
+ access: "create"
5381
+ }), method(z.object({
5382
+ code: z.string(),
5383
+ redirectUri: z.string()
5384
+ }), z.object({
5385
+ accessToken: z.string(),
5386
+ refreshToken: z.string(),
5387
+ expiresIn: z.number()
5388
+ }).nullable(), {
5389
+ kind: "mutation",
5390
+ access: "view"
5391
+ }), method(z.object({ refreshToken: z.string() }), z.object({
5392
+ accessToken: z.string(),
5393
+ refreshToken: z.string(),
5394
+ expiresIn: z.number()
5395
+ }).nullable(), {
5396
+ kind: "mutation",
5397
+ access: "view"
5398
+ }), method(z.object({ token: z.string() }), z.object({
5399
+ userId: z.string(),
5400
+ username: z.string(),
5401
+ scopes: z.array(TokenScopeSchema)
5402
+ }).nullable(), { access: "view" }), method(z.void(), z.array(OauthSessionSummarySchema), { auth: "admin" }), method(z.object({ id: z.string() }), z.object({ success: z.boolean() }), {
5403
+ kind: "mutation",
5404
+ auth: "admin",
5405
+ access: "delete"
5101
5406
  });
5102
5407
  var FeatureManifestSchema = z.object({
5103
5408
  streaming: z.boolean(),
@@ -5266,7 +5571,13 @@ method(z.void(), z.array(TopologyNodeSchema).readonly(), { auth: "admin" }), met
5266
5571
  }), RenameNodeResultSchema, {
5267
5572
  kind: "mutation",
5268
5573
  auth: "admin"
5269
- }), method(z.void(), z.record(z.string(), ClusterAddonStatusEntrySchema), { auth: "admin" }), method(z.object({ nodeId: z.string() }), z.array(NodeAddonEntrySchema).readonly(), { auth: "admin" }), method(z.object({
5574
+ }), method(z.void(), z.record(z.string(), ClusterAddonStatusEntrySchema), { auth: "admin" }), method(z.object({ windowSeconds: z.number().int().positive().max(300).default(60) }), z.array(z.object({
5575
+ callerAddonId: z.string(),
5576
+ providerAddonId: z.string(),
5577
+ capName: z.string(),
5578
+ callsPerMin: z.number(),
5579
+ lastCallAtMs: z.number()
5580
+ })).readonly(), { auth: "admin" }), method(z.object({ nodeId: z.string() }), z.array(NodeAddonEntrySchema).readonly(), { auth: "admin" }), method(z.object({
5270
5581
  nodeId: z.string(),
5271
5582
  level: z.string()
5272
5583
  }), SuccessSchema, {
@@ -7504,6 +7815,16 @@ var StorageManager = class {
7504
7815
  }
7505
7816
  };
7506
7817
  //#endregion
7818
+ //#region src/auth/scope-matcher.ts
7819
+ /**
7820
+ * True if the scope set grants `access` on device-scoped capabilities.
7821
+ * A `category:device` grant covers every device cap (the broad grant).
7822
+ * Mirrors the OR-semantics of the existing token scope matcher.
7823
+ */
7824
+ function scopesAllowDeviceCap(scopes, access) {
7825
+ return scopes.some((s) => s.type === "category" && s.target === "device" && s.access.includes(access));
7826
+ }
7827
+ //#endregion
7507
7828
  //#region src/notification/notification-service.ts
7508
7829
  /**
7509
7830
  * Central notification service that routes notifications to configured outputs.
@@ -8256,6 +8577,6 @@ var IntegrationRegistry = class {
8256
8577
  }
8257
8578
  };
8258
8579
  //#endregion
8259
- export { AddonApiFactory, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CORE_TABLE_DDL, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, DeviceManagerAddon, DeviceStore, EngineManagerResolver, EventBus, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FsStorageBackend, HubForwarderAddon, HubForwarderDestination, IntegrationRegistry, LifecycleStateMachine, LocalAuthAddon, LogManager, LogRingBuffer, ModelDownloadService, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, ReplEngine, ScopedLogger, ScopedTokenManager, SettingsStore, SqliteSettingsAddon, SqliteSettingsBackend, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, ToastService, UserManager, WinstonDestination, WinstonLoggingAddon, addonTableToDdl, buildBinaryPath, deleteModelFromDisk, downloadBinary, downloadFile, downloadModel, ensureBinary, ensureFfmpeg, ensureModel, ensurePython, ensureTlsCert, fetchJson, findInPath, formatLogLine, getFfmpegDownloadUrl, getModelFilePath, getPidStats, getPlatformInfo, getPythonDownloadUrl, getSinglePidStats, installPythonPackages, installPythonRequirements, isModelDownloaded, loadTlsCert };
8580
+ export { AddonApiFactory, AddonRouteRegistry, AlertCenterAddon, ApiKeyManager, AuthManager, CORE_TABLE_DDL, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, DeviceManagerAddon, DeviceStore, EngineManagerResolver, EventBus, FeatureManager, FilesystemStorageAddon, FilesystemStorageProvider, FsStorageBackend, HubForwarderAddon, HubForwarderDestination, IntegrationRegistry, LifecycleStateMachine, LocalAuthAddon, LogManager, LogRingBuffer, ModelDownloadService, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PythonEnvManager, ReplEngine, ScopedLogger, ScopedTokenManager, SettingsStore, SqliteSettingsAddon, SqliteSettingsBackend, StorageLocationManager, StorageManager, StorageOrchestratorAddon, StorageOrchestratorService, SystemConfigAddon, SystemEventBus, ToastService, UserManager, WinstonDestination, WinstonLoggingAddon, addonTableToDdl, buildBinaryPath, deleteModelFromDisk, downloadBinary, downloadFile, downloadModel, ensureBinary, ensureFfmpeg, ensureModel, ensurePython, ensureTlsCert, fetchJson, findInPath, formatLogLine, getFfmpegDownloadUrl, getModelFilePath, getPidStats, getPlatformInfo, getPythonDownloadUrl, getSinglePidStats, installPythonPackages, installPythonRequirements, isModelDownloaded, loadTlsCert, scopesAllowDeviceCap };
8260
8581
 
8261
8582
  //# sourceMappingURL=index.mjs.map