@camstack/addon-pipeline-orchestrator 0.1.14 → 0.1.15

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