@camstack/addon-import-alexa 0.2.130 → 0.2.131

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
@@ -7968,6 +7968,12 @@ function normalizeAddonInitResult(result) {
7968
7968
  if (Array.isArray(result)) return { providers: result };
7969
7969
  return result;
7970
7970
  }
7971
+ /**
7972
+ * The share-view scope kinds a `csv_*` share token can carry. The hub mints
7973
+ * and validates them (`share-token.service.ts` builds its enum from this
7974
+ * list); a data plane names the kinds it ACCEPTS in `share`.
7975
+ */
7976
+ var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
7971
7977
  /** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
7972
7978
  var PeerBytesTicketSchema = object({
7973
7979
  /** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
@@ -12950,6 +12956,229 @@ var ConvertResultSchema = object({
12950
12956
  files: array(string()).readonly()
12951
12957
  })).readonly()
12952
12958
  });
12959
+ /**
12960
+ * Zod schemas for persisted record types.
12961
+ *
12962
+ * These schemas serve as the single source of truth for types that are
12963
+ * stored in the settings-store backend and retrieved via tRPC. They
12964
+ * replace the manual TypeScript interfaces with schema-derived types,
12965
+ * enabling runtime validation when reading from the backend.
12966
+ *
12967
+ * Convention: each schema is named `<Type>Schema`, the inferred TS type
12968
+ * keeps the original name for backward compatibility.
12969
+ */
12970
+ /**
12971
+ * Auth model (v2 — 2026-05-12 caps-only):
12972
+ *
12973
+ * Two principals:
12974
+ * - `isAdmin: true` — full bypass. Admin scope set is ignored.
12975
+ * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
12976
+ *
12977
+ * No role enum. There used to be `viewer / agent / scoped` and earlier
12978
+ * `super_admin` — collapsed onto the single boolean because every
12979
+ * non-admin caller is governed by the same scope-check rules; the
12980
+ * distinction was only ever used to route role-specific procedures
12981
+ * which we no longer have. CLI / webhook integrations are `cst_*` tokens
12982
+ * with `isAdmin: false` + an explicit scope list.
12983
+ */
12984
+ /** Per-method access flavour. Materialised on every cap method via codegen. */
12985
+ var MethodAccessSchema = _enum([
12986
+ "view",
12987
+ "create",
12988
+ "delete"
12989
+ ]);
12990
+ /**
12991
+ * A single scope grant. Three forms — checked in matcher with OR
12992
+ * semantics; the first match decides whether the call passes:
12993
+ *
12994
+ * - `category` — broadest. `target: 'device' | 'system'` selects every
12995
+ * cap with the matching `scope` declaration. New caps inherit grants
12996
+ * automatically — adding a device cap to the codebase makes it
12997
+ * reachable to every user with `category:device [...]` without a
12998
+ * re-grant. Use this for "family viewer" / "operator" tiers.
12999
+ *
13000
+ * - `addon` — every cap that ships inside a given addon id. Niche;
13001
+ * useful when an integration needs to interact with one specific
13002
+ * addon's surface regardless of how many caps it exports.
13003
+ *
13004
+ * - `capability` — the most precise form. Single cap name. Use for
13005
+ * integration tokens where you want to grant `addons.installPackage`
13006
+ * and nothing else.
13007
+ *
13008
+ * `access` is REQUIRED with min 1 element. `admin` bypass is the
13009
+ * "give me everything" escape; there is no wildcard scope.
13010
+ */
13011
+ var AllowedProviderSchema = union([literal("*"), array(string())]);
13012
+ var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
13013
+ var CapScopeSchema = _enum(["device", "system"]);
13014
+ /**
13015
+ * DeviceSelector (scope model v3 — 2026-08-12).
13016
+ *
13017
+ * A `device` grant no longer carries a frozen list of deviceIds. It carries
13018
+ * a SELECTOR the matcher resolves against the live fleet, so the grant can be
13019
+ * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
13020
+ * AFTER the grant was minted — no re-grant, no re-login.
13021
+ *
13022
+ * - `all` — every device in the deployment. The broad viewer/operator
13023
+ * lever without a `category` grant (a `category` grant also covers device
13024
+ * caps that carry no deviceId; `all` is specifically the device set).
13025
+ * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
13026
+ * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
13027
+ * is NOT covered until the grant is edited.
13028
+ * - `types` — every device of a `DeviceType` (e.g. every `camera`).
13029
+ * DYNAMIC. A device that changes type, or a new device of the type,
13030
+ * re-resolves on the next request.
13031
+ * - `locations` — every device whose operator-assigned `location` label is
13032
+ * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
13033
+ * null/unset location matches NO `locations` selector.
13034
+ */
13035
+ var DeviceSelectorSchema = discriminatedUnion("kind", [
13036
+ object({ kind: literal("all") }),
13037
+ object({
13038
+ kind: literal("ids"),
13039
+ ids: array(number().int()).min(1)
13040
+ }),
13041
+ object({
13042
+ kind: literal("types"),
13043
+ types: array(_enum(DeviceType)).min(1)
13044
+ }),
13045
+ object({
13046
+ kind: literal("locations"),
13047
+ locations: array(string().min(1)).min(1)
13048
+ })
13049
+ ]);
13050
+ var DeviceTokenScopeSchema = object({
13051
+ type: literal("device"),
13052
+ /** The device SET this grant covers — resolved against the live fleet. */
13053
+ selector: DeviceSelectorSchema,
13054
+ access: array(MethodAccessSchema).min(1),
13055
+ /**
13056
+ * Whether a grant on a PARENT device transparently covers its accessory
13057
+ * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
13058
+ * Direction is parent → children ONLY.
13059
+ *
13060
+ * Absent → the matcher DERIVES it from the access flavour: `view`
13061
+ * inherits (a camera viewer sees the camera's accessories), `create` /
13062
+ * `delete` do NOT (actuating/removing a child is an explicit act the
13063
+ * operator must grant on the child, not inherit from the parent). Set it
13064
+ * explicitly to override that default per grant.
13065
+ */
13066
+ includeLinked: boolean().optional()
13067
+ });
13068
+ /**
13069
+ * v2 → v3 lazy migration. A pre-v3 `device` grant carried
13070
+ * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
13071
+ * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
13072
+ * EVERY parse path — stored records AND the JWT-carried scope arrays
13073
+ * normalised at the request boundary ({@link normalizeTokenScopes} in
13074
+ * `device-selector.ts`). Chosen over a one-time DB migration because a
13075
+ * migration cannot reach a JWT already in a client's hands; parse-time
13076
+ * migration covers both without a flag day. No cast — the raw object is read
13077
+ * through `Reflect.get` (its static type is `unknown`).
13078
+ */
13079
+ function migrateLegacyTokenScope(raw) {
13080
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
13081
+ if (Reflect.get(raw, "type") !== "device") return raw;
13082
+ if (Reflect.get(raw, "selector") !== void 0) return raw;
13083
+ const targets = Reflect.get(raw, "targets");
13084
+ if (!Array.isArray(targets)) return raw;
13085
+ return {
13086
+ type: "device",
13087
+ selector: {
13088
+ kind: "ids",
13089
+ ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
13090
+ },
13091
+ access: Reflect.get(raw, "access")
13092
+ };
13093
+ }
13094
+ var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
13095
+ object({
13096
+ type: literal("category"),
13097
+ target: CapScopeSchema,
13098
+ access: array(MethodAccessSchema).min(1)
13099
+ }),
13100
+ object({
13101
+ type: literal("capability"),
13102
+ target: string(),
13103
+ access: array(MethodAccessSchema).min(1)
13104
+ }),
13105
+ object({
13106
+ type: literal("addon"),
13107
+ target: string(),
13108
+ access: array(MethodAccessSchema).min(1)
13109
+ }),
13110
+ DeviceTokenScopeSchema
13111
+ ]));
13112
+ object({
13113
+ id: string(),
13114
+ username: string(),
13115
+ passwordHash: string(),
13116
+ /**
13117
+ * Admin bypass. When true, the middleware skips the scope-access
13118
+ * check entirely. There is no other axis of privilege; the legacy
13119
+ * role enum collapsed onto this boolean in v2.
13120
+ */
13121
+ isAdmin: boolean().default(false),
13122
+ allowedProviders: AllowedProviderSchema,
13123
+ allowedDevices: AllowedDevicesSchema,
13124
+ /**
13125
+ * Scopes granted to this user. Admins bypass; their `scopes` is
13126
+ * ignored. Non-admins without scopes are locked out of every
13127
+ * protected call.
13128
+ */
13129
+ scopes: array(TokenScopeSchema).default([]),
13130
+ createdAt: number(),
13131
+ updatedAt: number()
13132
+ });
13133
+ object({
13134
+ id: string(),
13135
+ label: string(),
13136
+ isAdmin: boolean().default(false),
13137
+ allowedProviders: AllowedProviderSchema,
13138
+ allowedDevices: AllowedDevicesSchema,
13139
+ tokenHash: string(),
13140
+ tokenPrefix: string(),
13141
+ createdAt: number(),
13142
+ lastUsedAt: number().optional()
13143
+ });
13144
+ object({
13145
+ id: string(),
13146
+ userId: string(),
13147
+ name: string(),
13148
+ tokenHash: string(),
13149
+ tokenPrefix: string(),
13150
+ scopes: array(TokenScopeSchema),
13151
+ expiresAt: number().nullish(),
13152
+ lastUsedAt: number().nullish(),
13153
+ createdAt: number()
13154
+ });
13155
+ /** What a share-view grant lets its holder see. */
13156
+ var ShareViewGrantSchema = object({
13157
+ kind: _enum(SHARE_VIEW_KINDS),
13158
+ deviceIds: array(number().int().nonnegative()).min(1).max(64),
13159
+ /** Talk-back, opt-in at mint time; absent means off. */
13160
+ talk: boolean().optional()
13161
+ });
13162
+ var ShareViewScopeSchema = object({
13163
+ type: literal("share-view"),
13164
+ grant: ShareViewGrantSchema
13165
+ });
13166
+ var AddonRoutesScopeSchema = object({
13167
+ type: literal("addon-routes"),
13168
+ access: array(MethodAccessSchema).min(1)
13169
+ });
13170
+ var CredentialScopeSchema = union([
13171
+ literal("*"),
13172
+ ShareViewScopeSchema,
13173
+ AddonRoutesScopeSchema,
13174
+ TokenScopeSchema
13175
+ ]);
13176
+ object({
13177
+ kind: literal("credential"),
13178
+ sub: string().min(1),
13179
+ jti: string().min(16),
13180
+ scopes: array(CredentialScopeSchema).min(1)
13181
+ });
12953
13182
  _enum(["new-session", "step-up"]);
12954
13183
  /** The languages the hub's app landing pages are written in (D858). */
12955
13184
  var AppPageLangSchema = _enum(["en", "it"]);
@@ -44512,202 +44741,6 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
44512
44741
  auth: "admin"
44513
44742
  }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
44514
44743
  /**
44515
- * Zod schemas for persisted record types.
44516
- *
44517
- * These schemas serve as the single source of truth for types that are
44518
- * stored in the settings-store backend and retrieved via tRPC. They
44519
- * replace the manual TypeScript interfaces with schema-derived types,
44520
- * enabling runtime validation when reading from the backend.
44521
- *
44522
- * Convention: each schema is named `<Type>Schema`, the inferred TS type
44523
- * keeps the original name for backward compatibility.
44524
- */
44525
- /**
44526
- * Auth model (v2 — 2026-05-12 caps-only):
44527
- *
44528
- * Two principals:
44529
- * - `isAdmin: true` — full bypass. Admin scope set is ignored.
44530
- * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
44531
- *
44532
- * No role enum. There used to be `viewer / agent / scoped` and earlier
44533
- * `super_admin` — collapsed onto the single boolean because every
44534
- * non-admin caller is governed by the same scope-check rules; the
44535
- * distinction was only ever used to route role-specific procedures
44536
- * which we no longer have. CLI / webhook integrations are `cst_*` tokens
44537
- * with `isAdmin: false` + an explicit scope list.
44538
- */
44539
- /** Per-method access flavour. Materialised on every cap method via codegen. */
44540
- var MethodAccessSchema = _enum([
44541
- "view",
44542
- "create",
44543
- "delete"
44544
- ]);
44545
- /**
44546
- * A single scope grant. Three forms — checked in matcher with OR
44547
- * semantics; the first match decides whether the call passes:
44548
- *
44549
- * - `category` — broadest. `target: 'device' | 'system'` selects every
44550
- * cap with the matching `scope` declaration. New caps inherit grants
44551
- * automatically — adding a device cap to the codebase makes it
44552
- * reachable to every user with `category:device [...]` without a
44553
- * re-grant. Use this for "family viewer" / "operator" tiers.
44554
- *
44555
- * - `addon` — every cap that ships inside a given addon id. Niche;
44556
- * useful when an integration needs to interact with one specific
44557
- * addon's surface regardless of how many caps it exports.
44558
- *
44559
- * - `capability` — the most precise form. Single cap name. Use for
44560
- * integration tokens where you want to grant `addons.installPackage`
44561
- * and nothing else.
44562
- *
44563
- * `access` is REQUIRED with min 1 element. `admin` bypass is the
44564
- * "give me everything" escape; there is no wildcard scope.
44565
- */
44566
- var AllowedProviderSchema = union([literal("*"), array(string())]);
44567
- var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
44568
- var CapScopeSchema = _enum(["device", "system"]);
44569
- /**
44570
- * DeviceSelector (scope model v3 — 2026-08-12).
44571
- *
44572
- * A `device` grant no longer carries a frozen list of deviceIds. It carries
44573
- * a SELECTOR the matcher resolves against the live fleet, so the grant can be
44574
- * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
44575
- * AFTER the grant was minted — no re-grant, no re-login.
44576
- *
44577
- * - `all` — every device in the deployment. The broad viewer/operator
44578
- * lever without a `category` grant (a `category` grant also covers device
44579
- * caps that carry no deviceId; `all` is specifically the device set).
44580
- * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
44581
- * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
44582
- * is NOT covered until the grant is edited.
44583
- * - `types` — every device of a `DeviceType` (e.g. every `camera`).
44584
- * DYNAMIC. A device that changes type, or a new device of the type,
44585
- * re-resolves on the next request.
44586
- * - `locations` — every device whose operator-assigned `location` label is
44587
- * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
44588
- * null/unset location matches NO `locations` selector.
44589
- */
44590
- var DeviceSelectorSchema = discriminatedUnion("kind", [
44591
- object({ kind: literal("all") }),
44592
- object({
44593
- kind: literal("ids"),
44594
- ids: array(number().int()).min(1)
44595
- }),
44596
- object({
44597
- kind: literal("types"),
44598
- types: array(_enum(DeviceType)).min(1)
44599
- }),
44600
- object({
44601
- kind: literal("locations"),
44602
- locations: array(string().min(1)).min(1)
44603
- })
44604
- ]);
44605
- var DeviceTokenScopeSchema = object({
44606
- type: literal("device"),
44607
- /** The device SET this grant covers — resolved against the live fleet. */
44608
- selector: DeviceSelectorSchema,
44609
- access: array(MethodAccessSchema).min(1),
44610
- /**
44611
- * Whether a grant on a PARENT device transparently covers its accessory
44612
- * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
44613
- * Direction is parent → children ONLY.
44614
- *
44615
- * Absent → the matcher DERIVES it from the access flavour: `view`
44616
- * inherits (a camera viewer sees the camera's accessories), `create` /
44617
- * `delete` do NOT (actuating/removing a child is an explicit act the
44618
- * operator must grant on the child, not inherit from the parent). Set it
44619
- * explicitly to override that default per grant.
44620
- */
44621
- includeLinked: boolean().optional()
44622
- });
44623
- /**
44624
- * v2 → v3 lazy migration. A pre-v3 `device` grant carried
44625
- * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
44626
- * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
44627
- * EVERY parse path — stored records AND the JWT-carried scope arrays
44628
- * normalised at the request boundary ({@link normalizeTokenScopes} in
44629
- * `device-selector.ts`). Chosen over a one-time DB migration because a
44630
- * migration cannot reach a JWT already in a client's hands; parse-time
44631
- * migration covers both without a flag day. No cast — the raw object is read
44632
- * through `Reflect.get` (its static type is `unknown`).
44633
- */
44634
- function migrateLegacyTokenScope(raw) {
44635
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
44636
- if (Reflect.get(raw, "type") !== "device") return raw;
44637
- if (Reflect.get(raw, "selector") !== void 0) return raw;
44638
- const targets = Reflect.get(raw, "targets");
44639
- if (!Array.isArray(targets)) return raw;
44640
- return {
44641
- type: "device",
44642
- selector: {
44643
- kind: "ids",
44644
- ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
44645
- },
44646
- access: Reflect.get(raw, "access")
44647
- };
44648
- }
44649
- var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
44650
- object({
44651
- type: literal("category"),
44652
- target: CapScopeSchema,
44653
- access: array(MethodAccessSchema).min(1)
44654
- }),
44655
- object({
44656
- type: literal("capability"),
44657
- target: string(),
44658
- access: array(MethodAccessSchema).min(1)
44659
- }),
44660
- object({
44661
- type: literal("addon"),
44662
- target: string(),
44663
- access: array(MethodAccessSchema).min(1)
44664
- }),
44665
- DeviceTokenScopeSchema
44666
- ]));
44667
- object({
44668
- id: string(),
44669
- username: string(),
44670
- passwordHash: string(),
44671
- /**
44672
- * Admin bypass. When true, the middleware skips the scope-access
44673
- * check entirely. There is no other axis of privilege; the legacy
44674
- * role enum collapsed onto this boolean in v2.
44675
- */
44676
- isAdmin: boolean().default(false),
44677
- allowedProviders: AllowedProviderSchema,
44678
- allowedDevices: AllowedDevicesSchema,
44679
- /**
44680
- * Scopes granted to this user. Admins bypass; their `scopes` is
44681
- * ignored. Non-admins without scopes are locked out of every
44682
- * protected call.
44683
- */
44684
- scopes: array(TokenScopeSchema).default([]),
44685
- createdAt: number(),
44686
- updatedAt: number()
44687
- });
44688
- object({
44689
- id: string(),
44690
- label: string(),
44691
- isAdmin: boolean().default(false),
44692
- allowedProviders: AllowedProviderSchema,
44693
- allowedDevices: AllowedDevicesSchema,
44694
- tokenHash: string(),
44695
- tokenPrefix: string(),
44696
- createdAt: number(),
44697
- lastUsedAt: number().optional()
44698
- });
44699
- object({
44700
- id: string(),
44701
- userId: string(),
44702
- name: string(),
44703
- tokenHash: string(),
44704
- tokenPrefix: string(),
44705
- scopes: array(TokenScopeSchema),
44706
- expiresAt: number().nullish(),
44707
- lastUsedAt: number().nullish(),
44708
- createdAt: number()
44709
- });
44710
- /**
44711
44744
  * `oauth-integration` — a collection cap by which an addon declares
44712
44745
  * itself a linkable OAuth client of the hub's core `/oauth2/*` server.
44713
44746
  * Each provider returns a static descriptor; the core enumerates them
package/dist/addon.mjs CHANGED
@@ -7968,6 +7968,12 @@ function normalizeAddonInitResult(result) {
7968
7968
  if (Array.isArray(result)) return { providers: result };
7969
7969
  return result;
7970
7970
  }
7971
+ /**
7972
+ * The share-view scope kinds a `csv_*` share token can carry. The hub mints
7973
+ * and validates them (`share-token.service.ts` builds its enum from this
7974
+ * list); a data plane names the kinds it ACCEPTS in `share`.
7975
+ */
7976
+ var SHARE_VIEW_KINDS = ["grid-view", "events-view"];
7971
7977
  /** The wire shape of {@link PeerBytesTicket} — see the type for what it is. */
7972
7978
  var PeerBytesTicketSchema = object({
7973
7979
  /** `http://127.0.0.1:<port>/<token>`. One `GET` takes it. */
@@ -12950,6 +12956,229 @@ var ConvertResultSchema = object({
12950
12956
  files: array(string()).readonly()
12951
12957
  })).readonly()
12952
12958
  });
12959
+ /**
12960
+ * Zod schemas for persisted record types.
12961
+ *
12962
+ * These schemas serve as the single source of truth for types that are
12963
+ * stored in the settings-store backend and retrieved via tRPC. They
12964
+ * replace the manual TypeScript interfaces with schema-derived types,
12965
+ * enabling runtime validation when reading from the backend.
12966
+ *
12967
+ * Convention: each schema is named `<Type>Schema`, the inferred TS type
12968
+ * keeps the original name for backward compatibility.
12969
+ */
12970
+ /**
12971
+ * Auth model (v2 — 2026-05-12 caps-only):
12972
+ *
12973
+ * Two principals:
12974
+ * - `isAdmin: true` — full bypass. Admin scope set is ignored.
12975
+ * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
12976
+ *
12977
+ * No role enum. There used to be `viewer / agent / scoped` and earlier
12978
+ * `super_admin` — collapsed onto the single boolean because every
12979
+ * non-admin caller is governed by the same scope-check rules; the
12980
+ * distinction was only ever used to route role-specific procedures
12981
+ * which we no longer have. CLI / webhook integrations are `cst_*` tokens
12982
+ * with `isAdmin: false` + an explicit scope list.
12983
+ */
12984
+ /** Per-method access flavour. Materialised on every cap method via codegen. */
12985
+ var MethodAccessSchema = _enum([
12986
+ "view",
12987
+ "create",
12988
+ "delete"
12989
+ ]);
12990
+ /**
12991
+ * A single scope grant. Three forms — checked in matcher with OR
12992
+ * semantics; the first match decides whether the call passes:
12993
+ *
12994
+ * - `category` — broadest. `target: 'device' | 'system'` selects every
12995
+ * cap with the matching `scope` declaration. New caps inherit grants
12996
+ * automatically — adding a device cap to the codebase makes it
12997
+ * reachable to every user with `category:device [...]` without a
12998
+ * re-grant. Use this for "family viewer" / "operator" tiers.
12999
+ *
13000
+ * - `addon` — every cap that ships inside a given addon id. Niche;
13001
+ * useful when an integration needs to interact with one specific
13002
+ * addon's surface regardless of how many caps it exports.
13003
+ *
13004
+ * - `capability` — the most precise form. Single cap name. Use for
13005
+ * integration tokens where you want to grant `addons.installPackage`
13006
+ * and nothing else.
13007
+ *
13008
+ * `access` is REQUIRED with min 1 element. `admin` bypass is the
13009
+ * "give me everything" escape; there is no wildcard scope.
13010
+ */
13011
+ var AllowedProviderSchema = union([literal("*"), array(string())]);
13012
+ var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
13013
+ var CapScopeSchema = _enum(["device", "system"]);
13014
+ /**
13015
+ * DeviceSelector (scope model v3 — 2026-08-12).
13016
+ *
13017
+ * A `device` grant no longer carries a frozen list of deviceIds. It carries
13018
+ * a SELECTOR the matcher resolves against the live fleet, so the grant can be
13019
+ * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
13020
+ * AFTER the grant was minted — no re-grant, no re-login.
13021
+ *
13022
+ * - `all` — every device in the deployment. The broad viewer/operator
13023
+ * lever without a `category` grant (a `category` grant also covers device
13024
+ * caps that carry no deviceId; `all` is specifically the device set).
13025
+ * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
13026
+ * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
13027
+ * is NOT covered until the grant is edited.
13028
+ * - `types` — every device of a `DeviceType` (e.g. every `camera`).
13029
+ * DYNAMIC. A device that changes type, or a new device of the type,
13030
+ * re-resolves on the next request.
13031
+ * - `locations` — every device whose operator-assigned `location` label is
13032
+ * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
13033
+ * null/unset location matches NO `locations` selector.
13034
+ */
13035
+ var DeviceSelectorSchema = discriminatedUnion("kind", [
13036
+ object({ kind: literal("all") }),
13037
+ object({
13038
+ kind: literal("ids"),
13039
+ ids: array(number().int()).min(1)
13040
+ }),
13041
+ object({
13042
+ kind: literal("types"),
13043
+ types: array(_enum(DeviceType)).min(1)
13044
+ }),
13045
+ object({
13046
+ kind: literal("locations"),
13047
+ locations: array(string().min(1)).min(1)
13048
+ })
13049
+ ]);
13050
+ var DeviceTokenScopeSchema = object({
13051
+ type: literal("device"),
13052
+ /** The device SET this grant covers — resolved against the live fleet. */
13053
+ selector: DeviceSelectorSchema,
13054
+ access: array(MethodAccessSchema).min(1),
13055
+ /**
13056
+ * Whether a grant on a PARENT device transparently covers its accessory
13057
+ * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
13058
+ * Direction is parent → children ONLY.
13059
+ *
13060
+ * Absent → the matcher DERIVES it from the access flavour: `view`
13061
+ * inherits (a camera viewer sees the camera's accessories), `create` /
13062
+ * `delete` do NOT (actuating/removing a child is an explicit act the
13063
+ * operator must grant on the child, not inherit from the parent). Set it
13064
+ * explicitly to override that default per grant.
13065
+ */
13066
+ includeLinked: boolean().optional()
13067
+ });
13068
+ /**
13069
+ * v2 → v3 lazy migration. A pre-v3 `device` grant carried
13070
+ * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
13071
+ * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
13072
+ * EVERY parse path — stored records AND the JWT-carried scope arrays
13073
+ * normalised at the request boundary ({@link normalizeTokenScopes} in
13074
+ * `device-selector.ts`). Chosen over a one-time DB migration because a
13075
+ * migration cannot reach a JWT already in a client's hands; parse-time
13076
+ * migration covers both without a flag day. No cast — the raw object is read
13077
+ * through `Reflect.get` (its static type is `unknown`).
13078
+ */
13079
+ function migrateLegacyTokenScope(raw) {
13080
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
13081
+ if (Reflect.get(raw, "type") !== "device") return raw;
13082
+ if (Reflect.get(raw, "selector") !== void 0) return raw;
13083
+ const targets = Reflect.get(raw, "targets");
13084
+ if (!Array.isArray(targets)) return raw;
13085
+ return {
13086
+ type: "device",
13087
+ selector: {
13088
+ kind: "ids",
13089
+ ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
13090
+ },
13091
+ access: Reflect.get(raw, "access")
13092
+ };
13093
+ }
13094
+ var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
13095
+ object({
13096
+ type: literal("category"),
13097
+ target: CapScopeSchema,
13098
+ access: array(MethodAccessSchema).min(1)
13099
+ }),
13100
+ object({
13101
+ type: literal("capability"),
13102
+ target: string(),
13103
+ access: array(MethodAccessSchema).min(1)
13104
+ }),
13105
+ object({
13106
+ type: literal("addon"),
13107
+ target: string(),
13108
+ access: array(MethodAccessSchema).min(1)
13109
+ }),
13110
+ DeviceTokenScopeSchema
13111
+ ]));
13112
+ object({
13113
+ id: string(),
13114
+ username: string(),
13115
+ passwordHash: string(),
13116
+ /**
13117
+ * Admin bypass. When true, the middleware skips the scope-access
13118
+ * check entirely. There is no other axis of privilege; the legacy
13119
+ * role enum collapsed onto this boolean in v2.
13120
+ */
13121
+ isAdmin: boolean().default(false),
13122
+ allowedProviders: AllowedProviderSchema,
13123
+ allowedDevices: AllowedDevicesSchema,
13124
+ /**
13125
+ * Scopes granted to this user. Admins bypass; their `scopes` is
13126
+ * ignored. Non-admins without scopes are locked out of every
13127
+ * protected call.
13128
+ */
13129
+ scopes: array(TokenScopeSchema).default([]),
13130
+ createdAt: number(),
13131
+ updatedAt: number()
13132
+ });
13133
+ object({
13134
+ id: string(),
13135
+ label: string(),
13136
+ isAdmin: boolean().default(false),
13137
+ allowedProviders: AllowedProviderSchema,
13138
+ allowedDevices: AllowedDevicesSchema,
13139
+ tokenHash: string(),
13140
+ tokenPrefix: string(),
13141
+ createdAt: number(),
13142
+ lastUsedAt: number().optional()
13143
+ });
13144
+ object({
13145
+ id: string(),
13146
+ userId: string(),
13147
+ name: string(),
13148
+ tokenHash: string(),
13149
+ tokenPrefix: string(),
13150
+ scopes: array(TokenScopeSchema),
13151
+ expiresAt: number().nullish(),
13152
+ lastUsedAt: number().nullish(),
13153
+ createdAt: number()
13154
+ });
13155
+ /** What a share-view grant lets its holder see. */
13156
+ var ShareViewGrantSchema = object({
13157
+ kind: _enum(SHARE_VIEW_KINDS),
13158
+ deviceIds: array(number().int().nonnegative()).min(1).max(64),
13159
+ /** Talk-back, opt-in at mint time; absent means off. */
13160
+ talk: boolean().optional()
13161
+ });
13162
+ var ShareViewScopeSchema = object({
13163
+ type: literal("share-view"),
13164
+ grant: ShareViewGrantSchema
13165
+ });
13166
+ var AddonRoutesScopeSchema = object({
13167
+ type: literal("addon-routes"),
13168
+ access: array(MethodAccessSchema).min(1)
13169
+ });
13170
+ var CredentialScopeSchema = union([
13171
+ literal("*"),
13172
+ ShareViewScopeSchema,
13173
+ AddonRoutesScopeSchema,
13174
+ TokenScopeSchema
13175
+ ]);
13176
+ object({
13177
+ kind: literal("credential"),
13178
+ sub: string().min(1),
13179
+ jti: string().min(16),
13180
+ scopes: array(CredentialScopeSchema).min(1)
13181
+ });
12953
13182
  _enum(["new-session", "step-up"]);
12954
13183
  /** The languages the hub's app landing pages are written in (D858). */
12955
13184
  var AppPageLangSchema = _enum(["en", "it"]);
@@ -44512,202 +44741,6 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
44512
44741
  auth: "admin"
44513
44742
  }), method(NcAlarmSensorsInputSchema, NcAlarmSensorsSchema, { auth: "admin" });
44514
44743
  /**
44515
- * Zod schemas for persisted record types.
44516
- *
44517
- * These schemas serve as the single source of truth for types that are
44518
- * stored in the settings-store backend and retrieved via tRPC. They
44519
- * replace the manual TypeScript interfaces with schema-derived types,
44520
- * enabling runtime validation when reading from the backend.
44521
- *
44522
- * Convention: each schema is named `<Type>Schema`, the inferred TS type
44523
- * keeps the original name for backward compatibility.
44524
- */
44525
- /**
44526
- * Auth model (v2 — 2026-05-12 caps-only):
44527
- *
44528
- * Two principals:
44529
- * - `isAdmin: true` — full bypass. Admin scope set is ignored.
44530
- * - `isAdmin: false` — every call gated by `scopes` (see TokenScope).
44531
- *
44532
- * No role enum. There used to be `viewer / agent / scoped` and earlier
44533
- * `super_admin` — collapsed onto the single boolean because every
44534
- * non-admin caller is governed by the same scope-check rules; the
44535
- * distinction was only ever used to route role-specific procedures
44536
- * which we no longer have. CLI / webhook integrations are `cst_*` tokens
44537
- * with `isAdmin: false` + an explicit scope list.
44538
- */
44539
- /** Per-method access flavour. Materialised on every cap method via codegen. */
44540
- var MethodAccessSchema = _enum([
44541
- "view",
44542
- "create",
44543
- "delete"
44544
- ]);
44545
- /**
44546
- * A single scope grant. Three forms — checked in matcher with OR
44547
- * semantics; the first match decides whether the call passes:
44548
- *
44549
- * - `category` — broadest. `target: 'device' | 'system'` selects every
44550
- * cap with the matching `scope` declaration. New caps inherit grants
44551
- * automatically — adding a device cap to the codebase makes it
44552
- * reachable to every user with `category:device [...]` without a
44553
- * re-grant. Use this for "family viewer" / "operator" tiers.
44554
- *
44555
- * - `addon` — every cap that ships inside a given addon id. Niche;
44556
- * useful when an integration needs to interact with one specific
44557
- * addon's surface regardless of how many caps it exports.
44558
- *
44559
- * - `capability` — the most precise form. Single cap name. Use for
44560
- * integration tokens where you want to grant `addons.installPackage`
44561
- * and nothing else.
44562
- *
44563
- * `access` is REQUIRED with min 1 element. `admin` bypass is the
44564
- * "give me everything" escape; there is no wildcard scope.
44565
- */
44566
- var AllowedProviderSchema = union([literal("*"), array(string())]);
44567
- var AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
44568
- var CapScopeSchema = _enum(["device", "system"]);
44569
- /**
44570
- * DeviceSelector (scope model v3 — 2026-08-12).
44571
- *
44572
- * A `device` grant no longer carries a frozen list of deviceIds. It carries
44573
- * a SELECTOR the matcher resolves against the live fleet, so the grant can be
44574
- * DYNAMIC: a `types:['camera']` selector automatically covers a camera added
44575
- * AFTER the grant was minted — no re-grant, no re-login.
44576
- *
44577
- * - `all` — every device in the deployment. The broad viewer/operator
44578
- * lever without a `category` grant (a `category` grant also covers device
44579
- * caps that carry no deviceId; `all` is specifically the device set).
44580
- * - `ids` — an explicit deviceId list. This is what a v2 `device:[…]`
44581
- * grant migrates to (see {@link TokenScopeSchema}); STATIC — a new camera
44582
- * is NOT covered until the grant is edited.
44583
- * - `types` — every device of a `DeviceType` (e.g. every `camera`).
44584
- * DYNAMIC. A device that changes type, or a new device of the type,
44585
- * re-resolves on the next request.
44586
- * - `locations` — every device whose operator-assigned `location` label is
44587
- * in the set (e.g. "Garden", "Front door"). DYNAMIC. A device with a
44588
- * null/unset location matches NO `locations` selector.
44589
- */
44590
- var DeviceSelectorSchema = discriminatedUnion("kind", [
44591
- object({ kind: literal("all") }),
44592
- object({
44593
- kind: literal("ids"),
44594
- ids: array(number().int()).min(1)
44595
- }),
44596
- object({
44597
- kind: literal("types"),
44598
- types: array(_enum(DeviceType)).min(1)
44599
- }),
44600
- object({
44601
- kind: literal("locations"),
44602
- locations: array(string().min(1)).min(1)
44603
- })
44604
- ]);
44605
- var DeviceTokenScopeSchema = object({
44606
- type: literal("device"),
44607
- /** The device SET this grant covers — resolved against the live fleet. */
44608
- selector: DeviceSelectorSchema,
44609
- access: array(MethodAccessSchema).min(1),
44610
- /**
44611
- * Whether a grant on a PARENT device transparently covers its accessory
44612
- * CHILDREN (siren / floodlight / PIR) via the persisted-parentage walk.
44613
- * Direction is parent → children ONLY.
44614
- *
44615
- * Absent → the matcher DERIVES it from the access flavour: `view`
44616
- * inherits (a camera viewer sees the camera's accessories), `create` /
44617
- * `delete` do NOT (actuating/removing a child is an explicit act the
44618
- * operator must grant on the child, not inherit from the parent). Set it
44619
- * explicitly to override that default per grant.
44620
- */
44621
- includeLinked: boolean().optional()
44622
- });
44623
- /**
44624
- * v2 → v3 lazy migration. A pre-v3 `device` grant carried
44625
- * `targets: string[]` (stringified deviceIds); it rewrites to the equivalent
44626
- * `selector: {kind:'ids', ids}`. Applied as a `preprocess` so it runs on
44627
- * EVERY parse path — stored records AND the JWT-carried scope arrays
44628
- * normalised at the request boundary ({@link normalizeTokenScopes} in
44629
- * `device-selector.ts`). Chosen over a one-time DB migration because a
44630
- * migration cannot reach a JWT already in a client's hands; parse-time
44631
- * migration covers both without a flag day. No cast — the raw object is read
44632
- * through `Reflect.get` (its static type is `unknown`).
44633
- */
44634
- function migrateLegacyTokenScope(raw) {
44635
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return raw;
44636
- if (Reflect.get(raw, "type") !== "device") return raw;
44637
- if (Reflect.get(raw, "selector") !== void 0) return raw;
44638
- const targets = Reflect.get(raw, "targets");
44639
- if (!Array.isArray(targets)) return raw;
44640
- return {
44641
- type: "device",
44642
- selector: {
44643
- kind: "ids",
44644
- ids: targets.map((t) => typeof t === "string" ? Number(t) : t).filter((n) => typeof n === "number" && Number.isInteger(n))
44645
- },
44646
- access: Reflect.get(raw, "access")
44647
- };
44648
- }
44649
- var TokenScopeSchema = preprocess(migrateLegacyTokenScope, discriminatedUnion("type", [
44650
- object({
44651
- type: literal("category"),
44652
- target: CapScopeSchema,
44653
- access: array(MethodAccessSchema).min(1)
44654
- }),
44655
- object({
44656
- type: literal("capability"),
44657
- target: string(),
44658
- access: array(MethodAccessSchema).min(1)
44659
- }),
44660
- object({
44661
- type: literal("addon"),
44662
- target: string(),
44663
- access: array(MethodAccessSchema).min(1)
44664
- }),
44665
- DeviceTokenScopeSchema
44666
- ]));
44667
- object({
44668
- id: string(),
44669
- username: string(),
44670
- passwordHash: string(),
44671
- /**
44672
- * Admin bypass. When true, the middleware skips the scope-access
44673
- * check entirely. There is no other axis of privilege; the legacy
44674
- * role enum collapsed onto this boolean in v2.
44675
- */
44676
- isAdmin: boolean().default(false),
44677
- allowedProviders: AllowedProviderSchema,
44678
- allowedDevices: AllowedDevicesSchema,
44679
- /**
44680
- * Scopes granted to this user. Admins bypass; their `scopes` is
44681
- * ignored. Non-admins without scopes are locked out of every
44682
- * protected call.
44683
- */
44684
- scopes: array(TokenScopeSchema).default([]),
44685
- createdAt: number(),
44686
- updatedAt: number()
44687
- });
44688
- object({
44689
- id: string(),
44690
- label: string(),
44691
- isAdmin: boolean().default(false),
44692
- allowedProviders: AllowedProviderSchema,
44693
- allowedDevices: AllowedDevicesSchema,
44694
- tokenHash: string(),
44695
- tokenPrefix: string(),
44696
- createdAt: number(),
44697
- lastUsedAt: number().optional()
44698
- });
44699
- object({
44700
- id: string(),
44701
- userId: string(),
44702
- name: string(),
44703
- tokenHash: string(),
44704
- tokenPrefix: string(),
44705
- scopes: array(TokenScopeSchema),
44706
- expiresAt: number().nullish(),
44707
- lastUsedAt: number().nullish(),
44708
- createdAt: number()
44709
- });
44710
- /**
44711
44744
  * `oauth-integration` — a collection cap by which an addon declares
44712
44745
  * itself a linkable OAuth client of the hub's core `/oauth2/*` server.
44713
44746
  * 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-import-alexa",
3
- "version": "0.2.130",
3
+ "version": "0.2.131",
4
4
  "description": "Alexa device-import provider for CamStack — imports the smart-home devices in a user's Alexa account via the unofficial alexa-remote2 cookie/token client (the inverse of the Alexa exporter)",
5
5
  "keywords": [
6
6
  "camstack",