@camstack/addon-pipeline-orchestrator 0.1.14 → 0.1.16

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 (24) hide show
  1. package/dist/@mf-types/compiled-types/widgets/MotionZonesEditor.d.ts +19 -0
  2. package/dist/@mf-types/compiled-types/widgets/MotionZonesEditor.d.ts.map +1 -0
  3. package/dist/@mf-types/compiled-types/widgets/index.d.ts +2 -0
  4. package/dist/@mf-types/compiled-types/widgets/index.d.ts.map +1 -1
  5. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionGridCanvas.d.ts +20 -0
  6. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionGridCanvas.d.ts.map +1 -0
  7. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionZonesOverlay.d.ts +14 -0
  8. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionZonesOverlay.d.ts.map +1 -0
  9. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionZonesTab.d.ts +5 -0
  10. package/dist/@mf-types/compiled-types/widgets/motion-zones/MotionZonesTab.d.ts.map +1 -0
  11. package/dist/@mf-types.zip +0 -0
  12. package/dist/__mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-UNj4rttw.mjs +20 -0
  13. package/dist/{__mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-DFjvaOLq.mjs → __mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-XtEtGou1.mjs} +4 -4
  14. package/dist/_stub.js +4502 -4259
  15. package/dist/{hostInit-ClDM91fS.mjs → hostInit-DMdjwivI.mjs} +3 -3
  16. package/dist/{index-culBovFl.mjs → index-BIlr4dIX.mjs} +1 -1
  17. package/dist/{index-BP0-1QYT.mjs → index-BK5-EWzN.mjs} +2792 -2506
  18. package/dist/{index-D3EnGJOk.mjs → index-BUn7hM0v.mjs} +2514 -2404
  19. package/dist/index.js +334 -79
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +334 -79
  22. package/dist/index.mjs.map +1 -1
  23. package/package.json +1 -1
  24. package/dist/__mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-DJg6MN3o.mjs +0 -20
package/dist/index.mjs CHANGED
@@ -5134,6 +5134,9 @@ function hydrateField(field, values) {
5134
5134
  return { ...field, value: items };
5135
5135
  }
5136
5136
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5137
+ if (field.type === "password") {
5138
+ return { ...field, value: "" };
5139
+ }
5137
5140
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5138
5141
  const hydrated = { ...field, value };
5139
5142
  return hydrated;
@@ -7343,6 +7346,34 @@ MotionTriggerStatusSchema.extend({
7343
7346
  }) }
7344
7347
  }
7345
7348
  });
7349
+ object({
7350
+ enabled: boolean(),
7351
+ sensitivity: number(),
7352
+ /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
7353
+ cells: array(boolean()),
7354
+ lastFetchedAt: number()
7355
+ });
7356
+ const MotionZoneOptionsSchema = object({
7357
+ gridWidth: number(),
7358
+ gridHeight: number(),
7359
+ sensitivity: object({ min: number(), max: number(), step: number() })
7360
+ });
7361
+ const MotionZonePatchSchema = object({
7362
+ enabled: boolean().optional(),
7363
+ sensitivity: number().optional(),
7364
+ cells: array(boolean()).optional()
7365
+ });
7366
+ ({
7367
+ deviceTypes: [DeviceType.Camera],
7368
+ methods: {
7369
+ getOptions: method(object({ deviceId: number() }), MotionZoneOptionsSchema),
7370
+ setZone: method(
7371
+ object({ deviceId: number(), patch: MotionZonePatchSchema }),
7372
+ _void(),
7373
+ { kind: "mutation", auth: "admin" }
7374
+ )
7375
+ }
7376
+ });
7346
7377
  const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
7347
7378
  const PtzAutotrackSettingsSchema = object({
7348
7379
  targetType: AutotrackTargetTypeSchema,
@@ -7431,6 +7462,72 @@ PtzAutotrackStatusSchema.extend({
7431
7462
  }) }
7432
7463
  }
7433
7464
  });
7465
+ const StreamProfileSchema = _enum(["main", "sub", "ext"]);
7466
+ const StreamProfileConfigSchema = object({
7467
+ width: number(),
7468
+ height: number(),
7469
+ codec: _enum(["h264", "h265"]),
7470
+ framerate: number(),
7471
+ bitrate: number(),
7472
+ // kbps
7473
+ bitrateMode: _enum(["vbr", "cbr"]).optional(),
7474
+ encoderProfile: _enum(["high", "main", "baseline"]).optional(),
7475
+ gop: number().optional(),
7476
+ audio: boolean().optional()
7477
+ });
7478
+ object({
7479
+ /** Per-profile current config. A profile absent = the camera doesn't have it. */
7480
+ main: StreamProfileConfigSchema.optional(),
7481
+ sub: StreamProfileConfigSchema.optional(),
7482
+ ext: StreamProfileConfigSchema.optional(),
7483
+ lastFetchedAt: number()
7484
+ });
7485
+ const StreamProfileOptionsSchema = object({
7486
+ resolutions: array(object({ width: number(), height: number() })),
7487
+ codecs: array(_enum(["h264", "h265"])),
7488
+ framerates: array(number()),
7489
+ /** Allowed bitrate values (kbps). Empty if the camera takes a free range. */
7490
+ bitrates: array(number()),
7491
+ /** Optional [min,max] kbps when the camera accepts a continuous range. */
7492
+ bitrateRange: tuple([number(), number()]).optional(),
7493
+ supportsBitrateMode: boolean(),
7494
+ supportsEncoderProfile: boolean(),
7495
+ supportsGop: boolean()
7496
+ });
7497
+ const StreamParamsOptionsSchema = object({
7498
+ main: StreamProfileOptionsSchema.optional(),
7499
+ sub: StreamProfileOptionsSchema.optional(),
7500
+ ext: StreamProfileOptionsSchema.optional()
7501
+ });
7502
+ const StreamProfilePatchSchema = object({
7503
+ width: number().optional(),
7504
+ height: number().optional(),
7505
+ codec: _enum(["h264", "h265"]).optional(),
7506
+ framerate: number().optional(),
7507
+ bitrate: number().optional(),
7508
+ bitrateMode: _enum(["vbr", "cbr"]).optional(),
7509
+ encoderProfile: _enum(["high", "main", "baseline"]).optional(),
7510
+ gop: number().optional(),
7511
+ audio: boolean().optional()
7512
+ });
7513
+ ({
7514
+ deviceTypes: [DeviceType.Camera],
7515
+ methods: {
7516
+ getOptions: method(
7517
+ object({ deviceId: number() }),
7518
+ StreamParamsOptionsSchema
7519
+ ),
7520
+ setProfile: method(
7521
+ object({
7522
+ deviceId: number(),
7523
+ profile: StreamProfileSchema,
7524
+ patch: StreamProfilePatchSchema
7525
+ }),
7526
+ _void(),
7527
+ { kind: "mutation", auth: "admin" }
7528
+ )
7529
+ }
7530
+ });
7434
7531
  object({
7435
7532
  on: boolean(),
7436
7533
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
@@ -8371,6 +8468,83 @@ const VersionOutputSchema = object({ version: string() });
8371
8468
  getVersion: method(_void(), VersionOutputSchema)
8372
8469
  }
8373
8470
  });
8471
+ const MethodAccessSchema = _enum(["view", "create", "delete"]);
8472
+ const AllowedProviderSchema = union([literal("*"), array(string())]);
8473
+ const AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
8474
+ const CapScopeSchema = _enum(["device", "system"]);
8475
+ const TokenScopeSchema = discriminatedUnion("type", [
8476
+ object({
8477
+ type: literal("category"),
8478
+ target: CapScopeSchema,
8479
+ access: array(MethodAccessSchema).min(1)
8480
+ }),
8481
+ object({
8482
+ type: literal("capability"),
8483
+ target: string(),
8484
+ access: array(MethodAccessSchema).min(1)
8485
+ }),
8486
+ object({
8487
+ type: literal("addon"),
8488
+ target: string(),
8489
+ access: array(MethodAccessSchema).min(1)
8490
+ }),
8491
+ object({
8492
+ type: literal("device"),
8493
+ /**
8494
+ * One or more deviceIds (serialised as strings for wire-format
8495
+ * consistency with the rest of the union). Matcher accepts if
8496
+ * `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
8497
+ * of one scope-per-device when granting access to a set of cameras.
8498
+ */
8499
+ targets: array(string()).min(1),
8500
+ access: array(MethodAccessSchema).min(1)
8501
+ })
8502
+ ]);
8503
+ object({
8504
+ id: string(),
8505
+ username: string(),
8506
+ passwordHash: string(),
8507
+ /**
8508
+ * Admin bypass. When true, the middleware skips the scope-access
8509
+ * check entirely. There is no other axis of privilege; the legacy
8510
+ * role enum collapsed onto this boolean in v2.
8511
+ */
8512
+ isAdmin: boolean().default(false),
8513
+ allowedProviders: AllowedProviderSchema,
8514
+ allowedDevices: AllowedDevicesSchema,
8515
+ /**
8516
+ * Scopes granted to this user. Admins bypass; their `scopes` is
8517
+ * ignored. Non-admins without scopes are locked out of every
8518
+ * protected call.
8519
+ */
8520
+ scopes: array(TokenScopeSchema).default([]),
8521
+ createdAt: number(),
8522
+ updatedAt: number()
8523
+ });
8524
+ object({
8525
+ id: string(),
8526
+ label: string(),
8527
+ isAdmin: boolean().default(false),
8528
+ allowedProviders: AllowedProviderSchema,
8529
+ allowedDevices: AllowedDevicesSchema,
8530
+ tokenHash: string(),
8531
+ tokenPrefix: string(),
8532
+ createdAt: number(),
8533
+ lastUsedAt: number().optional()
8534
+ });
8535
+ object({
8536
+ id: string(),
8537
+ userId: string(),
8538
+ name: string(),
8539
+ tokenHash: string(),
8540
+ tokenPrefix: string(),
8541
+ scopes: array(TokenScopeSchema),
8542
+ // SQLite/JSON storage round-trips undefined → null. Use `nullish` so the
8543
+ // schema accepts both `null` (read from disk) and `undefined` (in-memory).
8544
+ expiresAt: number().nullish(),
8545
+ lastUsedAt: number().nullish(),
8546
+ createdAt: number()
8547
+ });
8374
8548
  const SsoBridgeClaimsSchema = object({
8375
8549
  userId: string(),
8376
8550
  username: string(),
@@ -8386,7 +8560,18 @@ const SsoBridgeClaimsSchema = object({
8386
8560
  * JWT WITHOUT verifying the signature — the hub re-verifies on every
8387
8561
  * inbound call so trust still rests with the signing hub.
8388
8562
  */
8389
- hubUrl: string().optional()
8563
+ hubUrl: string().optional(),
8564
+ /** Permission scopes baked into the token. Set by the OAuth
8565
+ * account-linking grant; absent on ordinary SSO-login tokens. */
8566
+ scopes: array(TokenScopeSchema).optional(),
8567
+ /** OAuth authorization-code binding — set only on `oauth-code` tokens. */
8568
+ redirectUri: string().optional(),
8569
+ integrationId: string().optional(),
8570
+ /** JWT ID — unique per issued code; consumed-set enforces single-use. */
8571
+ jti: string().optional(),
8572
+ /** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
8573
+ * tokens so the verify path can check the session is not revoked. */
8574
+ sessionId: string().optional()
8390
8575
  });
8391
8576
  ({
8392
8577
  methods: {
@@ -8403,6 +8588,23 @@ const SsoBridgeClaimsSchema = object({
8403
8588
  )
8404
8589
  }
8405
8590
  });
8591
+ const OauthIntegrationDescriptorSchema = object({
8592
+ /** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
8593
+ integrationId: string(),
8594
+ /** Human label rendered on the consent page. */
8595
+ displayName: string(),
8596
+ /** Scopes baked into every token issued for this integration. */
8597
+ requestedScopes: array(TokenScopeSchema),
8598
+ /** Allowed redirect_uri prefixes. /oauth2/authorize rejects any
8599
+ * redirect_uri that does not start with one of these. Required —
8600
+ * an empty list means the integration can never complete linking. */
8601
+ allowedRedirectPrefixes: array(string()).min(1)
8602
+ });
8603
+ ({
8604
+ methods: {
8605
+ getDescriptor: method(_void(), OauthIntegrationDescriptorSchema)
8606
+ }
8607
+ });
8406
8608
  const PasskeySummarySchema = object({
8407
8609
  credentialId: string(),
8408
8610
  label: string(),
@@ -11076,6 +11278,14 @@ const PtzMoveCommandSchema = object({
11076
11278
  zoom: number().optional(),
11077
11279
  speed: number().optional()
11078
11280
  });
11281
+ const PtzOptionsSchema = object({
11282
+ hasPan: boolean(),
11283
+ hasTilt: boolean(),
11284
+ hasZoom: boolean(),
11285
+ supportsPresets: boolean(),
11286
+ /** Max number of named presets the camera supports, when known. */
11287
+ maxPresets: number().optional()
11288
+ });
11079
11289
  ({
11080
11290
  deviceTypes: [DeviceType.Camera],
11081
11291
  methods: {
@@ -11103,6 +11313,20 @@ const PtzMoveCommandSchema = object({
11103
11313
  _void(),
11104
11314
  { kind: "mutation" }
11105
11315
  ),
11316
+ savePreset: method(
11317
+ object({ deviceId: number(), presetId: string(), name: string() }),
11318
+ _void(),
11319
+ { kind: "mutation", auth: "admin" }
11320
+ ),
11321
+ deletePreset: method(
11322
+ object({ deviceId: number(), presetId: string() }),
11323
+ _void(),
11324
+ { kind: "mutation", auth: "admin" }
11325
+ ),
11326
+ getOptions: method(
11327
+ object({ deviceId: number() }),
11328
+ PtzOptionsSchema
11329
+ ),
11106
11330
  goHome: method(
11107
11331
  object({ deviceId: number() }),
11108
11332
  _void(),
@@ -12052,83 +12276,6 @@ const MeshStatusSchema = object({
12052
12276
  // tabs driven by this cap.
12053
12277
  }
12054
12278
  });
12055
- const MethodAccessSchema = _enum(["view", "create", "delete"]);
12056
- const AllowedProviderSchema = union([literal("*"), array(string())]);
12057
- const AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
12058
- const CapScopeSchema = _enum(["device", "system"]);
12059
- const TokenScopeSchema = discriminatedUnion("type", [
12060
- object({
12061
- type: literal("category"),
12062
- target: CapScopeSchema,
12063
- access: array(MethodAccessSchema).min(1)
12064
- }),
12065
- object({
12066
- type: literal("capability"),
12067
- target: string(),
12068
- access: array(MethodAccessSchema).min(1)
12069
- }),
12070
- object({
12071
- type: literal("addon"),
12072
- target: string(),
12073
- access: array(MethodAccessSchema).min(1)
12074
- }),
12075
- object({
12076
- type: literal("device"),
12077
- /**
12078
- * One or more deviceIds (serialised as strings for wire-format
12079
- * consistency with the rest of the union). Matcher accepts if
12080
- * `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
12081
- * of one scope-per-device when granting access to a set of cameras.
12082
- */
12083
- targets: array(string()).min(1),
12084
- access: array(MethodAccessSchema).min(1)
12085
- })
12086
- ]);
12087
- object({
12088
- id: string(),
12089
- username: string(),
12090
- passwordHash: string(),
12091
- /**
12092
- * Admin bypass. When true, the middleware skips the scope-access
12093
- * check entirely. There is no other axis of privilege; the legacy
12094
- * role enum collapsed onto this boolean in v2.
12095
- */
12096
- isAdmin: boolean().default(false),
12097
- allowedProviders: AllowedProviderSchema,
12098
- allowedDevices: AllowedDevicesSchema,
12099
- /**
12100
- * Scopes granted to this user. Admins bypass; their `scopes` is
12101
- * ignored. Non-admins without scopes are locked out of every
12102
- * protected call.
12103
- */
12104
- scopes: array(TokenScopeSchema).default([]),
12105
- createdAt: number(),
12106
- updatedAt: number()
12107
- });
12108
- object({
12109
- id: string(),
12110
- label: string(),
12111
- isAdmin: boolean().default(false),
12112
- allowedProviders: AllowedProviderSchema,
12113
- allowedDevices: AllowedDevicesSchema,
12114
- tokenHash: string(),
12115
- tokenPrefix: string(),
12116
- createdAt: number(),
12117
- lastUsedAt: number().optional()
12118
- });
12119
- object({
12120
- id: string(),
12121
- userId: string(),
12122
- name: string(),
12123
- tokenHash: string(),
12124
- tokenPrefix: string(),
12125
- scopes: array(TokenScopeSchema),
12126
- // SQLite/JSON storage round-trips undefined → null. Use `nullish` so the
12127
- // schema accepts both `null` (read from disk) and `undefined` (in-memory).
12128
- expiresAt: number().nullish(),
12129
- lastUsedAt: number().nullish(),
12130
- createdAt: number()
12131
- });
12132
12279
  const UserSummarySchema = object({
12133
12280
  id: string(),
12134
12281
  username: string(),
@@ -12201,6 +12348,16 @@ const CreateScopedTokenResultSchema = object({
12201
12348
  token: string(),
12202
12349
  record: ScopedTokenSummarySchema
12203
12350
  });
12351
+ const OauthSessionSummarySchema = object({
12352
+ id: string(),
12353
+ userId: string(),
12354
+ username: string(),
12355
+ integrationId: string(),
12356
+ scopes: array(TokenScopeSchema),
12357
+ createdAt: number(),
12358
+ lastUsedAt: number(),
12359
+ revokedAt: number().nullable()
12360
+ });
12204
12361
  const TotpSetupResultSchema = object({
12205
12362
  secret: string(),
12206
12363
  otpauthUrl: string()
@@ -12276,6 +12433,66 @@ const TotpStatusSchema = object({
12276
12433
  object({ userId: string(), code: string() }),
12277
12434
  object({ valid: boolean() }),
12278
12435
  { kind: "mutation", access: "view" }
12436
+ ),
12437
+ // ── OAuth account-linking grant ────────────────────────────────
12438
+ //
12439
+ // Core's /oauth2/* endpoints delegate here. Tokens are sso-bridge
12440
+ // JWTs (kinds oauth-code / oauth-access / oauth-refresh) and ALWAYS
12441
+ // carry isAdmin:false — the operator login proves hub control; the
12442
+ // issued token is minimal (device scope only).
12443
+ oauthIssueCode: method(
12444
+ object({
12445
+ integrationId: string(),
12446
+ userId: string(),
12447
+ username: string(),
12448
+ scopes: array(TokenScopeSchema),
12449
+ redirectUri: string(),
12450
+ hubUrl: string()
12451
+ }),
12452
+ object({ code: string() }),
12453
+ { kind: "mutation", access: "create" }
12454
+ ),
12455
+ oauthExchangeCode: method(
12456
+ object({ code: string(), redirectUri: string() }),
12457
+ object({
12458
+ accessToken: string(),
12459
+ refreshToken: string(),
12460
+ expiresIn: number()
12461
+ }).nullable(),
12462
+ { kind: "mutation", access: "view" }
12463
+ ),
12464
+ oauthRefresh: method(
12465
+ object({ refreshToken: string() }),
12466
+ object({
12467
+ accessToken: string(),
12468
+ refreshToken: string(),
12469
+ expiresIn: number()
12470
+ }).nullable(),
12471
+ { kind: "mutation", access: "view" }
12472
+ ),
12473
+ oauthVerifyAccessToken: method(
12474
+ object({ token: string() }),
12475
+ object({
12476
+ userId: string(),
12477
+ username: string(),
12478
+ scopes: array(TokenScopeSchema)
12479
+ }).nullable(),
12480
+ { access: "view" }
12481
+ ),
12482
+ // ── OAuth linked-session management (Phase D) ──────────────────
12483
+ //
12484
+ // The admin UI lists active account-linking sessions and revokes
12485
+ // them; revocation makes the linked integration's tokens fail
12486
+ // verification immediately.
12487
+ listOauthSessions: method(
12488
+ _void(),
12489
+ array(OauthSessionSummarySchema),
12490
+ { auth: "admin" }
12491
+ ),
12492
+ revokeOauthSession: method(
12493
+ object({ id: string() }),
12494
+ object({ success: boolean() }),
12495
+ { kind: "mutation", auth: "admin", access: "delete" }
12279
12496
  )
12280
12497
  }
12281
12498
  });
@@ -14778,6 +14995,24 @@ class PipelineOrchestratorAddon extends BaseAddon {
14778
14995
  allowedSizes: ["lg", "xl"],
14779
14996
  defaultColumns: 12,
14780
14997
  defaultRows: 4
14998
+ },
14999
+ {
15000
+ // On-camera motion-detection grid editor. The `motion-zones`
15001
+ // cap is owned by the camera provider addons; the widget only
15002
+ // talks to it over tRPC, so hosting the React surface here
15003
+ // (one bundle) avoids duplicating it per provider.
15004
+ stableId: "motion-zones-editor",
15005
+ label: "Motion Zones",
15006
+ description: "On-camera motion-detection grid editor (live-frame overlay).",
15007
+ icon: "grid-3x3",
15008
+ remoteName: "addon_pipeline_orchestrator_widgets",
15009
+ bundle: "remoteEntry.js",
15010
+ hosts: ["device-tab"],
15011
+ requires: { deviceContext: true, integrationContext: false },
15012
+ defaultSize: "lg",
15013
+ allowedSizes: ["md", "lg"],
15014
+ defaultColumns: 12,
15015
+ defaultRows: 1
14781
15016
  }
14782
15017
  ]
14783
15018
  };
@@ -16949,8 +17184,28 @@ class PipelineOrchestratorAddon extends BaseAddon {
16949
17184
  }
16950
17185
  ]
16951
17186
  };
17187
+ const motionZonesSection = {
17188
+ id: "motion-zones",
17189
+ title: "Motion Zones",
17190
+ tab: "motion",
17191
+ location: "settings",
17192
+ columns: 1,
17193
+ order: 0,
17194
+ fields: [
17195
+ {
17196
+ // Widget fields manage their own state via DeviceProxy —
17197
+ // `ConfigWidgetField` carries no `value` (unlike the legacy
17198
+ // `zone-editor` field type which still does).
17199
+ type: "widget",
17200
+ key: "motion-zones",
17201
+ label: "Motion Zones",
17202
+ widgetId: "pipeline-orchestrator/motion-zones-editor",
17203
+ span: 1
17204
+ }
17205
+ ]
17206
+ };
16952
17207
  return {
16953
- sections: [...baseSections, zonesSection]
17208
+ sections: [...baseSections, zonesSection, motionZonesSection]
16954
17209
  };
16955
17210
  }
16956
17211
  // `getCameraPipelineWithFallback` was a thin wrapper over