@camstack/addon-provider-onvif 1.2.131 → 1.2.132

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 (3) hide show
  1. package/dist/addon.js +229 -196
  2. package/dist/addon.mjs +229 -196
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7799,6 +7799,12 @@ function normalizeAddonInitResult(result) {
7799
7799
  if (Array.isArray(result)) return { providers: result };
7800
7800
  return result;
7801
7801
  }
7802
+ /**
7803
+ * The share-view scope kinds a `csv_*` share token can carry. The hub mints
7804
+ * and validates them (`share-token.service.ts` builds its enum from this
7805
+ * list); a data plane names the kinds it ACCEPTS in `share`.
7806
+ */
7807
+ var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
7802
7808
  /** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
7803
7809
  var PeerBytesTicketSchema = object({
7804
7810
  /** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
@@ -12393,6 +12399,229 @@ var ConvertResultSchema = object({
12393
12399
  files: array(string()).readonly()
12394
12400
  })).readonly()
12395
12401
  });
12402
+ /**
12403
+ * Zod schemas for persisted record types.
12404
+ *
12405
+ * These schemas serve as the single source of truth for types that are
12406
+ * stored in the settings-store backend and retrieved via tRPC. They
12407
+ * replace the manual TypeScript interfaces with schema-derived types,
12408
+ * enabling runtime validation when reading from the backend.
12409
+ *
12410
+ * Convention: each schema is named `<Type>Schema`, the inferred TS type
12411
+ * keeps the original name for backward compatibility.
12412
+ */
12413
+ /**
12414
+ * Auth model (v2 — 2026-05-12 caps-only):
12415
+ *
12416
+ * Two principals:
12417
+ * - `isAdmin: true` — full bypass. Admin scope set is ignored.
12418
+ * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
12419
+ *
12420
+ * No role enum. There used to be `viewer / agent / scoped` and earlier
12421
+ * `super_admin` — collapsed onto the single boolean because every
12422
+ * non-admin caller is governed by the same scope-check rules; the
12423
+ * distinction was only ever used to route role-specific procedures
12424
+ * which we no longer have. CLI / webhook integrations are `cst_*` tokens
12425
+ * with `isAdmin: false` + an explicit scope list.
12426
+ */
12427
+ /** Per-method access flavour. Materialised on every cap method via codegen. */
12428
+ var MethodAccessSchema = _enum([
12429
+ "view",
12430
+ "create",
12431
+ "delete"
12432
+ ]);
12433
+ /**
12434
+ * A single scope grant. Three forms — checked in matcher with OR
12435
+ * semantics; the first match decides whether the call passes:
12436
+ *
12437
+ * - `category` — broadest. `target: 'device' | 'system'` selects every
12438
+ * cap with the matching `scope` declaration. New caps inherit grants
12439
+ * automatically — adding a device cap to the codebase makes it
12440
+ * reachable to every user with `category:device [...]` without a
12441
+ * re-grant. Use this for "family viewer" / "operator" tiers.
12442
+ *
12443
+ * - `addon` — every cap that ships inside a given addon id. Niche;
12444
+ * useful when an integration needs to interact with one specific
12445
+ * addon's surface regardless of how many caps it exports.
12446
+ *
12447
+ * - `capability` — the most precise form. Single cap name. Use for
12448
+ * integration tokens where you want to grant `addons.installPackage`
12449
+ * and nothing else.
12450
+ *
12451
+ * `access` is REQUIRED with min 1 element. `admin` bypass is the
12452
+ * "give me everything" escape; there is no wildcard scope.
12453
+ */
12454
+ var AllowedProviderSchema = union([literal("*"), array(string())]);
12455
+ var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
12456
+ var CapScopeSchema = _enum(["device", "system"]);
12457
+ /**
12458
+ * DeviceSelector (scope model v3 — 2026-08-12).
12459
+ *
12460
+ * A `device` grant no longer carries a frozen list of deviceIds. It carries
12461
+ * a SELECTOR the matcher resolves against the live fleet, so the grant can be
12462
+ * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
12463
+ * AFTER the grant was minted — no re-grant, no re-login.
12464
+ *
12465
+ * - `all` — every device in the deployment. The broad viewer/operator
12466
+ * lever without a `category` grant (a `category` grant also covers device
12467
+ * caps that carry no deviceId; `all` is specifically the device set).
12468
+ * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
12469
+ * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
12470
+ * is NOT covered until the grant is edited.
12471
+ * - `types` — every device of a `DeviceType` (e.g. every `camera`).
12472
+ * DYNAMIC. A device that changes type, or a new device of the type,
12473
+ * re-resolves on the next request.
12474
+ * - `locations` — every device whose operator-assigned `location` label is
12475
+ * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
12476
+ * null/unset location matches NO `locations` selector.
12477
+ */
12478
+ var DeviceSelectorSchema = discriminatedUnion("kind", [
12479
+ object({ kind: literal("all") }),
12480
+ object({
12481
+ kind: literal("ids"),
12482
+ ids: array(number().int()).min(1)
12483
+ }),
12484
+ object({
12485
+ kind: literal("types"),
12486
+ types: array(_enum(DeviceType)).min(1)
12487
+ }),
12488
+ object({
12489
+ kind: literal("locations"),
12490
+ locations: array(string().min(1)).min(1)
12491
+ })
12492
+ ]);
12493
+ var DeviceTokenScopeSchema = object({
12494
+ type: literal("device"),
12495
+ /** The device SET this grant covers — resolved against the live fleet. */
12496
+ selector: DeviceSelectorSchema,
12497
+ access: array(MethodAccessSchema).min(1),
12498
+ /**
12499
+ * Whether a grant on a PARENT device transparently covers its accessory
12500
+ * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
12501
+ * Direction is parent → children ONLY.
12502
+ *
12503
+ * Absent → the matcher DERIVES it from the access flavour: `view`
12504
+ * inherits (a camera viewer sees the camera's accessories), `create` /
12505
+ * `delete` do NOT (actuating/removing a child is an explicit act the
12506
+ * operator must grant on the child, not inherit from the parent). Set it
12507
+ * explicitly to override that default per grant.
12508
+ */
12509
+ includeLinked: boolean().optional()
12510
+ });
12511
+ /**
12512
+ * v2 → v3 lazy migration. A pre-v3 `device` grant carried
12513
+ * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
12514
+ * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
12515
+ * EVERY parse path — stored records AND the JWT-carried scope arrays
12516
+ * normalised at the request boundary ({@link normalizeTokenScopes} in
12517
+ * `device-selector.ts`). Chosen over a one-time DB migration because a
12518
+ * migration cannot reach a JWT already in a client's hands; parse-time
12519
+ * migration covers both without a flag day. No cast — the raw object is read
12520
+ * through `Reflect.get` (its static type is `unknown`).
12521
+ */
12522
+ function migrateLegacyTokenScope(raw) {
12523
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
12524
+ if (Reflect.get(raw, "type") !== "device") return raw;
12525
+ if (Reflect.get(raw, "selector") !== void 0) return raw;
12526
+ const targets = Reflect.get(raw, "targets");
12527
+ if (!Array.isArray(targets)) return raw;
12528
+ return {
12529
+ type: "device",
12530
+ selector: {
12531
+ kind: "ids",
12532
+ ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
12533
+ },
12534
+ access: Reflect.get(raw, "access")
12535
+ };
12536
+ }
12537
+ var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
12538
+ object({
12539
+ type: literal("category"),
12540
+ target: CapScopeSchema,
12541
+ access: array(MethodAccessSchema).min(1)
12542
+ }),
12543
+ object({
12544
+ type: literal("capability"),
12545
+ target: string(),
12546
+ access: array(MethodAccessSchema).min(1)
12547
+ }),
12548
+ object({
12549
+ type: literal("addon"),
12550
+ target: string(),
12551
+ access: array(MethodAccessSchema).min(1)
12552
+ }),
12553
+ DeviceTokenScopeSchema
12554
+ ]));
12555
+ object({
12556
+ id: string(),
12557
+ username: string(),
12558
+ passwordHash: string(),
12559
+ /**
12560
+ * Admin bypass. When true, the middleware skips the scope-access
12561
+ * check entirely. There is no other axis of privilege; the legacy
12562
+ * role enum collapsed onto this boolean in v2.
12563
+ */
12564
+ isAdmin: boolean().default(false),
12565
+ allowedProviders: AllowedProviderSchema,
12566
+ allowedDevices: AllowedDevicesSchema,
12567
+ /**
12568
+ * Scopes granted to this user. Admins bypass; their `scopes` is
12569
+ * ignored. Non-admins without scopes are locked out of every
12570
+ * protected call.
12571
+ */
12572
+ scopes: array(TokenScopeSchema).default([]),
12573
+ createdAt: number(),
12574
+ updatedAt: number()
12575
+ });
12576
+ object({
12577
+ id: string(),
12578
+ label: string(),
12579
+ isAdmin: boolean().default(false),
12580
+ allowedProviders: AllowedProviderSchema,
12581
+ allowedDevices: AllowedDevicesSchema,
12582
+ tokenHash: string(),
12583
+ tokenPrefix: string(),
12584
+ createdAt: number(),
12585
+ lastUsedAt: number().optional()
12586
+ });
12587
+ object({
12588
+ id: string(),
12589
+ userId: string(),
12590
+ name: string(),
12591
+ tokenHash: string(),
12592
+ tokenPrefix: string(),
12593
+ scopes: array(TokenScopeSchema),
12594
+ expiresAt: number().nullish(),
12595
+ lastUsedAt: number().nullish(),
12596
+ createdAt: number()
12597
+ });
12598
+ /** What a share-view grant lets its holder see. */
12599
+ var ShareViewGrantSchema = object({
12600
+ kind: _enum(SHARE_VIEW_KINDS),
12601
+ deviceIds: array(number().int().nonnegative()).min(1).max(64),
12602
+ /** Talk-back, opt-in at mint time; absent means off. */
12603
+ talk: boolean().optional()
12604
+ });
12605
+ var ShareViewScopeSchema = object({
12606
+ type: literal("share-view"),
12607
+ grant: ShareViewGrantSchema
12608
+ });
12609
+ var AddonRoutesScopeSchema = object({
12610
+ type: literal("addon-routes"),
12611
+ access: array(MethodAccessSchema).min(1)
12612
+ });
12613
+ var CredentialScopeSchema = union([
12614
+ literal("*"),
12615
+ ShareViewScopeSchema,
12616
+ AddonRoutesScopeSchema,
12617
+ TokenScopeSchema
12618
+ ]);
12619
+ object({
12620
+ kind: literal("credential"),
12621
+ sub: string().min(1),
12622
+ jti: string().min(16),
12623
+ scopes: array(CredentialScopeSchema).min(1)
12624
+ });
12396
12625
  _enum(["new-session", "step-up"]);
12397
12626
  /** The languages the hub's app landing pages are written in (D858). */
12398
12627
  var AppPageLangSchema = _enum(["en", "it"]);
@@ -43724,202 +43953,6 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
43724
43953
  auth: "admin"
43725
43954
  }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
43726
43955
  /**
43727
- * Zod schemas for persisted record types.
43728
- *
43729
- * These schemas serve as the single source of truth for types that are
43730
- * stored in the settings-store backend and retrieved via tRPC. They
43731
- * replace the manual TypeScript interfaces with schema-derived types,
43732
- * enabling runtime validation when reading from the backend.
43733
- *
43734
- * Convention: each schema is named `<Type>Schema`, the inferred TS type
43735
- * keeps the original name for backward compatibility.
43736
- */
43737
- /**
43738
- * Auth model (v2 — 2026-05-12 caps-only):
43739
- *
43740
- * Two principals:
43741
- * - `isAdmin: true` — full bypass. Admin scope set is ignored.
43742
- * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
43743
- *
43744
- * No role enum. There used to be `viewer / agent / scoped` and earlier
43745
- * `super_admin` — collapsed onto the single boolean because every
43746
- * non-admin caller is governed by the same scope-check rules; the
43747
- * distinction was only ever used to route role-specific procedures
43748
- * which we no longer have. CLI / webhook integrations are `cst_*` tokens
43749
- * with `isAdmin: false` + an explicit scope list.
43750
- */
43751
- /** Per-method access flavour. Materialised on every cap method via codegen. */
43752
- var MethodAccessSchema = _enum([
43753
- "view",
43754
- "create",
43755
- "delete"
43756
- ]);
43757
- /**
43758
- * A single scope grant. Three forms — checked in matcher with OR
43759
- * semantics; the first match decides whether the call passes:
43760
- *
43761
- * - `category` — broadest. `target: 'device' | 'system'` selects every
43762
- * cap with the matching `scope` declaration. New caps inherit grants
43763
- * automatically — adding a device cap to the codebase makes it
43764
- * reachable to every user with `category:device [...]` without a
43765
- * re-grant. Use this for "family viewer" / "operator" tiers.
43766
- *
43767
- * - `addon` — every cap that ships inside a given addon id. Niche;
43768
- * useful when an integration needs to interact with one specific
43769
- * addon's surface regardless of how many caps it exports.
43770
- *
43771
- * - `capability` — the most precise form. Single cap name. Use for
43772
- * integration tokens where you want to grant `addons.installPackage`
43773
- * and nothing else.
43774
- *
43775
- * `access` is REQUIRED with min 1 element. `admin` bypass is the
43776
- * "give me everything" escape; there is no wildcard scope.
43777
- */
43778
- var AllowedProviderSchema = union([literal("*"), array(string())]);
43779
- var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
43780
- var CapScopeSchema = _enum(["device", "system"]);
43781
- /**
43782
- * DeviceSelector (scope model v3 — 2026-08-12).
43783
- *
43784
- * A `device` grant no longer carries a frozen list of deviceIds. It carries
43785
- * a SELECTOR the matcher resolves against the live fleet, so the grant can be
43786
- * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
43787
- * AFTER the grant was minted — no re-grant, no re-login.
43788
- *
43789
- * - `all` — every device in the deployment. The broad viewer/operator
43790
- * lever without a `category` grant (a `category` grant also covers device
43791
- * caps that carry no deviceId; `all` is specifically the device set).
43792
- * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
43793
- * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
43794
- * is NOT covered until the grant is edited.
43795
- * - `types` — every device of a `DeviceType` (e.g. every `camera`).
43796
- * DYNAMIC. A device that changes type, or a new device of the type,
43797
- * re-resolves on the next request.
43798
- * - `locations` — every device whose operator-assigned `location` label is
43799
- * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
43800
- * null/unset location matches NO `locations` selector.
43801
- */
43802
- var DeviceSelectorSchema = discriminatedUnion("kind", [
43803
- object({ kind: literal("all") }),
43804
- object({
43805
- kind: literal("ids"),
43806
- ids: array(number().int()).min(1)
43807
- }),
43808
- object({
43809
- kind: literal("types"),
43810
- types: array(_enum(DeviceType)).min(1)
43811
- }),
43812
- object({
43813
- kind: literal("locations"),
43814
- locations: array(string().min(1)).min(1)
43815
- })
43816
- ]);
43817
- var DeviceTokenScopeSchema = object({
43818
- type: literal("device"),
43819
- /** The device SET this grant covers — resolved against the live fleet. */
43820
- selector: DeviceSelectorSchema,
43821
- access: array(MethodAccessSchema).min(1),
43822
- /**
43823
- * Whether a grant on a PARENT device transparently covers its accessory
43824
- * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
43825
- * Direction is parent → children ONLY.
43826
- *
43827
- * Absent → the matcher DERIVES it from the access flavour: `view`
43828
- * inherits (a camera viewer sees the camera's accessories), `create` /
43829
- * `delete` do NOT (actuating/removing a child is an explicit act the
43830
- * operator must grant on the child, not inherit from the parent). Set it
43831
- * explicitly to override that default per grant.
43832
- */
43833
- includeLinked: boolean().optional()
43834
- });
43835
- /**
43836
- * v2 → v3 lazy migration. A pre-v3 `device` grant carried
43837
- * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
43838
- * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
43839
- * EVERY parse path — stored records AND the JWT-carried scope arrays
43840
- * normalised at the request boundary ({@link normalizeTokenScopes} in
43841
- * `device-selector.ts`). Chosen over a one-time DB migration because a
43842
- * migration cannot reach a JWT already in a client's hands; parse-time
43843
- * migration covers both without a flag day. No cast — the raw object is read
43844
- * through `Reflect.get` (its static type is `unknown`).
43845
- */
43846
- function migrateLegacyTokenScope(raw) {
43847
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
43848
- if (Reflect.get(raw, "type") !== "device") return raw;
43849
- if (Reflect.get(raw, "selector") !== void 0) return raw;
43850
- const targets = Reflect.get(raw, "targets");
43851
- if (!Array.isArray(targets)) return raw;
43852
- return {
43853
- type: "device",
43854
- selector: {
43855
- kind: "ids",
43856
- ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
43857
- },
43858
- access: Reflect.get(raw, "access")
43859
- };
43860
- }
43861
- var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
43862
- object({
43863
- type: literal("category"),
43864
- target: CapScopeSchema,
43865
- access: array(MethodAccessSchema).min(1)
43866
- }),
43867
- object({
43868
- type: literal("capability"),
43869
- target: string(),
43870
- access: array(MethodAccessSchema).min(1)
43871
- }),
43872
- object({
43873
- type: literal("addon"),
43874
- target: string(),
43875
- access: array(MethodAccessSchema).min(1)
43876
- }),
43877
- DeviceTokenScopeSchema
43878
- ]));
43879
- object({
43880
- id: string(),
43881
- username: string(),
43882
- passwordHash: string(),
43883
- /**
43884
- * Admin bypass. When true, the middleware skips the scope-access
43885
- * check entirely. There is no other axis of privilege; the legacy
43886
- * role enum collapsed onto this boolean in v2.
43887
- */
43888
- isAdmin: boolean().default(false),
43889
- allowedProviders: AllowedProviderSchema,
43890
- allowedDevices: AllowedDevicesSchema,
43891
- /**
43892
- * Scopes granted to this user. Admins bypass; their `scopes` is
43893
- * ignored. Non-admins without scopes are locked out of every
43894
- * protected call.
43895
- */
43896
- scopes: array(TokenScopeSchema).default([]),
43897
- createdAt: number(),
43898
- updatedAt: number()
43899
- });
43900
- object({
43901
- id: string(),
43902
- label: string(),
43903
- isAdmin: boolean().default(false),
43904
- allowedProviders: AllowedProviderSchema,
43905
- allowedDevices: AllowedDevicesSchema,
43906
- tokenHash: string(),
43907
- tokenPrefix: string(),
43908
- createdAt: number(),
43909
- lastUsedAt: number().optional()
43910
- });
43911
- object({
43912
- id: string(),
43913
- userId: string(),
43914
- name: string(),
43915
- tokenHash: string(),
43916
- tokenPrefix: string(),
43917
- scopes: array(TokenScopeSchema),
43918
- expiresAt: number().nullish(),
43919
- lastUsedAt: number().nullish(),
43920
- createdAt: number()
43921
- });
43922
- /**
43923
43956
  * `oauth-integration` — a collection cap by which an addon declares
43924
43957
  * itself a linkable OAuth client of the hub's core `/oauth2/*` server.
43925
43958
  * Each provider returns a static descriptor; the core enumerates them
package/dist/addon.mjs CHANGED
@@ -7800,6 +7800,12 @@ function normalizeAddonInitResult(result) {
7800
7800
  if (Array.isArray(result)) return { providers: result };
7801
7801
  return result;
7802
7802
  }
7803
+ /**
7804
+ * The share-view scope kinds a `csv_*` share token can carry. The hub mints
7805
+ * and validates them (`share-token.service.ts` builds its enum from this
7806
+ * list); a data plane names the kinds it ACCEPTS in `share`.
7807
+ */
7808
+ var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
7803
7809
  /** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
7804
7810
  var PeerBytesTicketSchema = object({
7805
7811
  /** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
@@ -12394,6 +12400,229 @@ var ConvertResultSchema = object({
12394
12400
  files: array(string()).readonly()
12395
12401
  })).readonly()
12396
12402
  });
12403
+ /**
12404
+ * Zod schemas for persisted record types.
12405
+ *
12406
+ * These schemas serve as the single source of truth for types that are
12407
+ * stored in the settings-store backend and retrieved via tRPC. They
12408
+ * replace the manual TypeScript interfaces with schema-derived types,
12409
+ * enabling runtime validation when reading from the backend.
12410
+ *
12411
+ * Convention: each schema is named `<Type>Schema`, the inferred TS type
12412
+ * keeps the original name for backward compatibility.
12413
+ */
12414
+ /**
12415
+ * Auth model (v2 — 2026-05-12 caps-only):
12416
+ *
12417
+ * Two principals:
12418
+ * - `isAdmin: true` — full bypass. Admin scope set is ignored.
12419
+ * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
12420
+ *
12421
+ * No role enum. There used to be `viewer / agent / scoped` and earlier
12422
+ * `super_admin` — collapsed onto the single boolean because every
12423
+ * non-admin caller is governed by the same scope-check rules; the
12424
+ * distinction was only ever used to route role-specific procedures
12425
+ * which we no longer have. CLI / webhook integrations are `cst_*` tokens
12426
+ * with `isAdmin: false` + an explicit scope list.
12427
+ */
12428
+ /** Per-method access flavour. Materialised on every cap method via codegen. */
12429
+ var MethodAccessSchema = _enum([
12430
+ "view",
12431
+ "create",
12432
+ "delete"
12433
+ ]);
12434
+ /**
12435
+ * A single scope grant. Three forms — checked in matcher with OR
12436
+ * semantics; the first match decides whether the call passes:
12437
+ *
12438
+ * - `category` — broadest. `target: 'device' | 'system'` selects every
12439
+ * cap with the matching `scope` declaration. New caps inherit grants
12440
+ * automatically — adding a device cap to the codebase makes it
12441
+ * reachable to every user with `category:device [...]` without a
12442
+ * re-grant. Use this for "family viewer" / "operator" tiers.
12443
+ *
12444
+ * - `addon` — every cap that ships inside a given addon id. Niche;
12445
+ * useful when an integration needs to interact with one specific
12446
+ * addon's surface regardless of how many caps it exports.
12447
+ *
12448
+ * - `capability` — the most precise form. Single cap name. Use for
12449
+ * integration tokens where you want to grant `addons.installPackage`
12450
+ * and nothing else.
12451
+ *
12452
+ * `access` is REQUIRED with min 1 element. `admin` bypass is the
12453
+ * "give me everything" escape; there is no wildcard scope.
12454
+ */
12455
+ var AllowedProviderSchema = union([literal("*"), array(string())]);
12456
+ var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
12457
+ var CapScopeSchema = _enum(["device", "system"]);
12458
+ /**
12459
+ * DeviceSelector (scope model v3 — 2026-08-12).
12460
+ *
12461
+ * A `device` grant no longer carries a frozen list of deviceIds. It carries
12462
+ * a SELECTOR the matcher resolves against the live fleet, so the grant can be
12463
+ * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
12464
+ * AFTER the grant was minted — no re-grant, no re-login.
12465
+ *
12466
+ * - `all` — every device in the deployment. The broad viewer/operator
12467
+ * lever without a `category` grant (a `category` grant also covers device
12468
+ * caps that carry no deviceId; `all` is specifically the device set).
12469
+ * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
12470
+ * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
12471
+ * is NOT covered until the grant is edited.
12472
+ * - `types` — every device of a `DeviceType` (e.g. every `camera`).
12473
+ * DYNAMIC. A device that changes type, or a new device of the type,
12474
+ * re-resolves on the next request.
12475
+ * - `locations` — every device whose operator-assigned `location` label is
12476
+ * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
12477
+ * null/unset location matches NO `locations` selector.
12478
+ */
12479
+ var DeviceSelectorSchema = discriminatedUnion("kind", [
12480
+ object({ kind: literal("all") }),
12481
+ object({
12482
+ kind: literal("ids"),
12483
+ ids: array(number().int()).min(1)
12484
+ }),
12485
+ object({
12486
+ kind: literal("types"),
12487
+ types: array(_enum(DeviceType)).min(1)
12488
+ }),
12489
+ object({
12490
+ kind: literal("locations"),
12491
+ locations: array(string().min(1)).min(1)
12492
+ })
12493
+ ]);
12494
+ var DeviceTokenScopeSchema = object({
12495
+ type: literal("device"),
12496
+ /** The device SET this grant covers — resolved against the live fleet. */
12497
+ selector: DeviceSelectorSchema,
12498
+ access: array(MethodAccessSchema).min(1),
12499
+ /**
12500
+ * Whether a grant on a PARENT device transparently covers its accessory
12501
+ * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
12502
+ * Direction is parent → children ONLY.
12503
+ *
12504
+ * Absent → the matcher DERIVES it from the access flavour: `view`
12505
+ * inherits (a camera viewer sees the camera's accessories), `create` /
12506
+ * `delete` do NOT (actuating/removing a child is an explicit act the
12507
+ * operator must grant on the child, not inherit from the parent). Set it
12508
+ * explicitly to override that default per grant.
12509
+ */
12510
+ includeLinked: boolean().optional()
12511
+ });
12512
+ /**
12513
+ * v2 → v3 lazy migration. A pre-v3 `device` grant carried
12514
+ * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
12515
+ * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
12516
+ * EVERY parse path — stored records AND the JWT-carried scope arrays
12517
+ * normalised at the request boundary ({@link normalizeTokenScopes} in
12518
+ * `device-selector.ts`). Chosen over a one-time DB migration because a
12519
+ * migration cannot reach a JWT already in a client's hands; parse-time
12520
+ * migration covers both without a flag day. No cast — the raw object is read
12521
+ * through `Reflect.get` (its static type is `unknown`).
12522
+ */
12523
+ function migrateLegacyTokenScope(raw) {
12524
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
12525
+ if (Reflect.get(raw, "type") !== "device") return raw;
12526
+ if (Reflect.get(raw, "selector") !== void 0) return raw;
12527
+ const targets = Reflect.get(raw, "targets");
12528
+ if (!Array.isArray(targets)) return raw;
12529
+ return {
12530
+ type: "device",
12531
+ selector: {
12532
+ kind: "ids",
12533
+ ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
12534
+ },
12535
+ access: Reflect.get(raw, "access")
12536
+ };
12537
+ }
12538
+ var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
12539
+ object({
12540
+ type: literal("category"),
12541
+ target: CapScopeSchema,
12542
+ access: array(MethodAccessSchema).min(1)
12543
+ }),
12544
+ object({
12545
+ type: literal("capability"),
12546
+ target: string(),
12547
+ access: array(MethodAccessSchema).min(1)
12548
+ }),
12549
+ object({
12550
+ type: literal("addon"),
12551
+ target: string(),
12552
+ access: array(MethodAccessSchema).min(1)
12553
+ }),
12554
+ DeviceTokenScopeSchema
12555
+ ]));
12556
+ object({
12557
+ id: string(),
12558
+ username: string(),
12559
+ passwordHash: string(),
12560
+ /**
12561
+ * Admin bypass. When true, the middleware skips the scope-access
12562
+ * check entirely. There is no other axis of privilege; the legacy
12563
+ * role enum collapsed onto this boolean in v2.
12564
+ */
12565
+ isAdmin: boolean().default(false),
12566
+ allowedProviders: AllowedProviderSchema,
12567
+ allowedDevices: AllowedDevicesSchema,
12568
+ /**
12569
+ * Scopes granted to this user. Admins bypass; their `scopes` is
12570
+ * ignored. Non-admins without scopes are locked out of every
12571
+ * protected call.
12572
+ */
12573
+ scopes: array(TokenScopeSchema).default([]),
12574
+ createdAt: number(),
12575
+ updatedAt: number()
12576
+ });
12577
+ object({
12578
+ id: string(),
12579
+ label: string(),
12580
+ isAdmin: boolean().default(false),
12581
+ allowedProviders: AllowedProviderSchema,
12582
+ allowedDevices: AllowedDevicesSchema,
12583
+ tokenHash: string(),
12584
+ tokenPrefix: string(),
12585
+ createdAt: number(),
12586
+ lastUsedAt: number().optional()
12587
+ });
12588
+ object({
12589
+ id: string(),
12590
+ userId: string(),
12591
+ name: string(),
12592
+ tokenHash: string(),
12593
+ tokenPrefix: string(),
12594
+ scopes: array(TokenScopeSchema),
12595
+ expiresAt: number().nullish(),
12596
+ lastUsedAt: number().nullish(),
12597
+ createdAt: number()
12598
+ });
12599
+ /** What a share-view grant lets its holder see. */
12600
+ var ShareViewGrantSchema = object({
12601
+ kind: _enum(SHARE_VIEW_KINDS),
12602
+ deviceIds: array(number().int().nonnegative()).min(1).max(64),
12603
+ /** Talk-back, opt-in at mint time; absent means off. */
12604
+ talk: boolean().optional()
12605
+ });
12606
+ var ShareViewScopeSchema = object({
12607
+ type: literal("share-view"),
12608
+ grant: ShareViewGrantSchema
12609
+ });
12610
+ var AddonRoutesScopeSchema = object({
12611
+ type: literal("addon-routes"),
12612
+ access: array(MethodAccessSchema).min(1)
12613
+ });
12614
+ var CredentialScopeSchema = union([
12615
+ literal("*"),
12616
+ ShareViewScopeSchema,
12617
+ AddonRoutesScopeSchema,
12618
+ TokenScopeSchema
12619
+ ]);
12620
+ object({
12621
+ kind: literal("credential"),
12622
+ sub: string().min(1),
12623
+ jti: string().min(16),
12624
+ scopes: array(CredentialScopeSchema).min(1)
12625
+ });
12397
12626
  _enum(["new-session", "step-up"]);
12398
12627
  /** The languages the hub's app landing pages are written in (D858). */
12399
12628
  var AppPageLangSchema = _enum(["en", "it"]);
@@ -43725,202 +43954,6 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
43725
43954
  auth: "admin"
43726
43955
  }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
43727
43956
  /**
43728
- * Zod schemas for persisted record types.
43729
- *
43730
- * These schemas serve as the single source of truth for types that are
43731
- * stored in the settings-store backend and retrieved via tRPC. They
43732
- * replace the manual TypeScript interfaces with schema-derived types,
43733
- * enabling runtime validation when reading from the backend.
43734
- *
43735
- * Convention: each schema is named `<Type>Schema`, the inferred TS type
43736
- * keeps the original name for backward compatibility.
43737
- */
43738
- /**
43739
- * Auth model (v2 — 2026-05-12 caps-only):
43740
- *
43741
- * Two principals:
43742
- * - `isAdmin: true` — full bypass. Admin scope set is ignored.
43743
- * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
43744
- *
43745
- * No role enum. There used to be `viewer / agent / scoped` and earlier
43746
- * `super_admin` — collapsed onto the single boolean because every
43747
- * non-admin caller is governed by the same scope-check rules; the
43748
- * distinction was only ever used to route role-specific procedures
43749
- * which we no longer have. CLI / webhook integrations are `cst_*` tokens
43750
- * with `isAdmin: false` + an explicit scope list.
43751
- */
43752
- /** Per-method access flavour. Materialised on every cap method via codegen. */
43753
- var MethodAccessSchema = _enum([
43754
- "view",
43755
- "create",
43756
- "delete"
43757
- ]);
43758
- /**
43759
- * A single scope grant. Three forms — checked in matcher with OR
43760
- * semantics; the first match decides whether the call passes:
43761
- *
43762
- * - `category` — broadest. `target: 'device' | 'system'` selects every
43763
- * cap with the matching `scope` declaration. New caps inherit grants
43764
- * automatically — adding a device cap to the codebase makes it
43765
- * reachable to every user with `category:device [...]` without a
43766
- * re-grant. Use this for "family viewer" / "operator" tiers.
43767
- *
43768
- * - `addon` — every cap that ships inside a given addon id. Niche;
43769
- * useful when an integration needs to interact with one specific
43770
- * addon's surface regardless of how many caps it exports.
43771
- *
43772
- * - `capability` — the most precise form. Single cap name. Use for
43773
- * integration tokens where you want to grant `addons.installPackage`
43774
- * and nothing else.
43775
- *
43776
- * `access` is REQUIRED with min 1 element. `admin` bypass is the
43777
- * "give me everything" escape; there is no wildcard scope.
43778
- */
43779
- var AllowedProviderSchema = union([literal("*"), array(string())]);
43780
- var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
43781
- var CapScopeSchema = _enum(["device", "system"]);
43782
- /**
43783
- * DeviceSelector (scope model v3 — 2026-08-12).
43784
- *
43785
- * A `device` grant no longer carries a frozen list of deviceIds. It carries
43786
- * a SELECTOR the matcher resolves against the live fleet, so the grant can be
43787
- * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
43788
- * AFTER the grant was minted — no re-grant, no re-login.
43789
- *
43790
- * - `all` — every device in the deployment. The broad viewer/operator
43791
- * lever without a `category` grant (a `category` grant also covers device
43792
- * caps that carry no deviceId; `all` is specifically the device set).
43793
- * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
43794
- * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
43795
- * is NOT covered until the grant is edited.
43796
- * - `types` — every device of a `DeviceType` (e.g. every `camera`).
43797
- * DYNAMIC. A device that changes type, or a new device of the type,
43798
- * re-resolves on the next request.
43799
- * - `locations` — every device whose operator-assigned `location` label is
43800
- * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
43801
- * null/unset location matches NO `locations` selector.
43802
- */
43803
- var DeviceSelectorSchema = discriminatedUnion("kind", [
43804
- object({ kind: literal("all") }),
43805
- object({
43806
- kind: literal("ids"),
43807
- ids: array(number().int()).min(1)
43808
- }),
43809
- object({
43810
- kind: literal("types"),
43811
- types: array(_enum(DeviceType)).min(1)
43812
- }),
43813
- object({
43814
- kind: literal("locations"),
43815
- locations: array(string().min(1)).min(1)
43816
- })
43817
- ]);
43818
- var DeviceTokenScopeSchema = object({
43819
- type: literal("device"),
43820
- /** The device SET this grant covers — resolved against the live fleet. */
43821
- selector: DeviceSelectorSchema,
43822
- access: array(MethodAccessSchema).min(1),
43823
- /**
43824
- * Whether a grant on a PARENT device transparently covers its accessory
43825
- * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
43826
- * Direction is parent → children ONLY.
43827
- *
43828
- * Absent → the matcher DERIVES it from the access flavour: `view`
43829
- * inherits (a camera viewer sees the camera's accessories), `create` /
43830
- * `delete` do NOT (actuating/removing a child is an explicit act the
43831
- * operator must grant on the child, not inherit from the parent). Set it
43832
- * explicitly to override that default per grant.
43833
- */
43834
- includeLinked: boolean().optional()
43835
- });
43836
- /**
43837
- * v2 → v3 lazy migration. A pre-v3 `device` grant carried
43838
- * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
43839
- * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
43840
- * EVERY parse path — stored records AND the JWT-carried scope arrays
43841
- * normalised at the request boundary ({@link normalizeTokenScopes} in
43842
- * `device-selector.ts`). Chosen over a one-time DB migration because a
43843
- * migration cannot reach a JWT already in a client's hands; parse-time
43844
- * migration covers both without a flag day. No cast — the raw object is read
43845
- * through `Reflect.get` (its static type is `unknown`).
43846
- */
43847
- function migrateLegacyTokenScope(raw) {
43848
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
43849
- if (Reflect.get(raw, "type") !== "device") return raw;
43850
- if (Reflect.get(raw, "selector") !== void 0) return raw;
43851
- const targets = Reflect.get(raw, "targets");
43852
- if (!Array.isArray(targets)) return raw;
43853
- return {
43854
- type: "device",
43855
- selector: {
43856
- kind: "ids",
43857
- ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
43858
- },
43859
- access: Reflect.get(raw, "access")
43860
- };
43861
- }
43862
- var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
43863
- object({
43864
- type: literal("category"),
43865
- target: CapScopeSchema,
43866
- access: array(MethodAccessSchema).min(1)
43867
- }),
43868
- object({
43869
- type: literal("capability"),
43870
- target: string(),
43871
- access: array(MethodAccessSchema).min(1)
43872
- }),
43873
- object({
43874
- type: literal("addon"),
43875
- target: string(),
43876
- access: array(MethodAccessSchema).min(1)
43877
- }),
43878
- DeviceTokenScopeSchema
43879
- ]));
43880
- object({
43881
- id: string(),
43882
- username: string(),
43883
- passwordHash: string(),
43884
- /**
43885
- * Admin bypass. When true, the middleware skips the scope-access
43886
- * check entirely. There is no other axis of privilege; the legacy
43887
- * role enum collapsed onto this boolean in v2.
43888
- */
43889
- isAdmin: boolean().default(false),
43890
- allowedProviders: AllowedProviderSchema,
43891
- allowedDevices: AllowedDevicesSchema,
43892
- /**
43893
- * Scopes granted to this user. Admins bypass; their `scopes` is
43894
- * ignored. Non-admins without scopes are locked out of every
43895
- * protected call.
43896
- */
43897
- scopes: array(TokenScopeSchema).default([]),
43898
- createdAt: number(),
43899
- updatedAt: number()
43900
- });
43901
- object({
43902
- id: string(),
43903
- label: string(),
43904
- isAdmin: boolean().default(false),
43905
- allowedProviders: AllowedProviderSchema,
43906
- allowedDevices: AllowedDevicesSchema,
43907
- tokenHash: string(),
43908
- tokenPrefix: string(),
43909
- createdAt: number(),
43910
- lastUsedAt: number().optional()
43911
- });
43912
- object({
43913
- id: string(),
43914
- userId: string(),
43915
- name: string(),
43916
- tokenHash: string(),
43917
- tokenPrefix: string(),
43918
- scopes: array(TokenScopeSchema),
43919
- expiresAt: number().nullish(),
43920
- lastUsedAt: number().nullish(),
43921
- createdAt: number()
43922
- });
43923
- /**
43924
43957
  * `oauth-integration` — a collection cap by which an addon declares
43925
43958
  * itself a linkable OAuth client of the hub's core `/oauth2/*` server.
43926
43959
  * Each provider returns a static descriptor; the core enumerates them
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-onvif",
3
- "version": "1.2.131",
3
+ "version": "1.2.132",
4
4
  "description": "ONVIF camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",