@camstack/addon-pipeline 1.2.52 → 1.2.54

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 (37) hide show
  1. package/dist/{addon-utils-DveoBR6G.js → addon-utils-CQs-AjTJ.js} +177 -177
  2. package/dist/{addon-utils-QuxtOdK1.mjs → addon-utils-CZ2xo67g.mjs} +177 -177
  3. package/dist/audio-analyzer/index.js +2 -2
  4. package/dist/audio-analyzer/index.mjs +2 -2
  5. package/dist/detection-pipeline/index.js +3 -3
  6. package/dist/detection-pipeline/index.mjs +3 -3
  7. package/dist/{dist-gB3o0cyM.mjs → dist-B55xTTsS.mjs} +368 -5
  8. package/dist/{dist-CzFJeiG1.js → dist-D8TX_P_A.js} +368 -5
  9. package/dist/{event-loop-stall-monitor-DSPDQYjc.js → event-loop-stall-monitor-Bs6d-u_F.js} +1 -1
  10. package/dist/{event-loop-stall-monitor-PxIaVeyh.mjs → event-loop-stall-monitor-Cq_KOlfb.mjs} +1 -1
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/pipeline-runner/index.js +75 -25
  14. package/dist/pipeline-runner/index.mjs +75 -25
  15. package/dist/recorder/index.js +2 -2
  16. package/dist/recorder/index.mjs +2 -2
  17. package/dist/session-decode/decode-worker-child.js +6 -2
  18. package/dist/session-decode/decode-worker-child.mjs +6 -2
  19. package/dist/stream-broker/_stub.js +2 -2
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DAeBhR8B.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C-9q6y1s.mjs} +3 -3
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CAmiVOsA.mjs +26 -0
  22. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CaGsMvou.mjs +26 -0
  23. package/dist/stream-broker/{hostInit-DniAXKLy.mjs → hostInit-DiXYwnXH.mjs} +3 -3
  24. package/dist/stream-broker/index.js +2 -2
  25. package/dist/stream-broker/index.mjs +2 -2
  26. package/dist/stream-broker/remoteEntry.js +1 -1
  27. package/dist/{worker-protocol-BhhX7J4-.mjs → worker-protocol-Bol291_n.mjs} +1 -1
  28. package/dist/{worker-protocol-BQlELGzv.js → worker-protocol-C2uctCrd.js} +1 -1
  29. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-B1gpA9sI.js → MaskShapeCanvas-DI4BY7W2-DY1AX2y_.js} +1 -1
  30. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-DV6vvNDq.js → MotionZonesSettings-NcxxQN8r-D46Ft0YB.js} +1 -1
  31. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-BmUdRoZ9.js → PrivacyMaskSettings-APgPLF7p-BLD9p-W3.js} +1 -1
  32. package/embed-dist/assets/{index-ICnBEqOy.css → index-C68W664Z.css} +1 -1
  33. package/embed-dist/assets/{index-DsGzhGCW.js → index-CWxqVyhE.js} +12 -12
  34. package/embed-dist/index.html +2 -2
  35. package/package.json +1 -1
  36. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bl9zivOk.mjs +0 -26
  37. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Czrsozsg.mjs +0 -26
@@ -8045,6 +8045,104 @@ object({
8045
8045
  })
8046
8046
  });
8047
8047
  /**
8048
+ * Adoption job — the background form of `device-adoption.adopt`.
8049
+ *
8050
+ * ## Why this exists
8051
+ *
8052
+ * `adopt({childNativeIds: [...]})` materialises one CamStack device per
8053
+ * candidate PLUS every accessory child, and the whole array shares ONE UDS
8054
+ * request deadline (60s). Measured on the live hub against Home Assistant:
8055
+ * each device the kernel creates costs ~450 ms — `devices.create` pre-seeds
8056
+ * meta with up to eleven SEQUENTIAL round trips (`setName`, `setType`,
8057
+ * `setRole`, … `persistConfig`) before the class is constructed — and an
8058
+ * accessory child costs the same as its parent. So the real unit of work is
8059
+ * the CHILD, not the candidate:
8060
+ *
8061
+ * - 25 candidates averaging 6 children → ~150 devices → **>60s, times out**
8062
+ * - ONE candidate with 217 children → ~217 devices → **>60s, times out**
8063
+ *
8064
+ * That second line is why this is a job and not a smaller batch. No chunking,
8065
+ * no bounded concurrency over candidates and no per-call tuning can fix a
8066
+ * shape where **N=1 already exceeds the deadline** — the count that blows the
8067
+ * budget is the source system's accessory fan-out, which the operator does not
8068
+ * choose and cannot see. A design that only works below some N is the same bug
8069
+ * deferred.
8070
+ *
8071
+ * ## What the timeout did NOT do
8072
+ *
8073
+ * It did not stop the work. The UDS deadline ends the CALLER's wait; the
8074
+ * provider's loop runs to completion. Measured: a 25-candidate adopt that
8075
+ * "failed" at 60s had adopted 17 by 87s and all 25 by ~130s. The operator saw
8076
+ * an error and had no way to learn that. Every field below exists so that
8077
+ * question has an answer.
8078
+ *
8079
+ * ## Idempotency
8080
+ *
8081
+ * Jobs are in-RAM; a restart forgets them. That is safe here because adoption
8082
+ * is keyed by a stable id (`ha:<broker>:dev:<nativeId>` and equivalents), so
8083
+ * re-running a job re-adopts nothing: an already-adopted candidate is SKIPPED
8084
+ * by the engine before any provider call and lands in `alreadyAdopted`. It is
8085
+ * never a duplicate device, and never an error the operator has to interpret.
8086
+ */
8087
+ var AdoptionJobStateSchema = _enum([
8088
+ "running",
8089
+ "done",
8090
+ "failed",
8091
+ "cancelled"
8092
+ ]);
8093
+ /**
8094
+ * Per-candidate result. Every candidate the job was asked to adopt ends in
8095
+ * exactly one of these buckets — there is no silent drop, and the operator can
8096
+ * always answer "which of my 25 landed?".
8097
+ *
8098
+ * - `adopted` — created now by this job.
8099
+ * - `already-adopted` — a device for this candidate existed before the job
8100
+ * reached it (a re-run, or a retry after a timeout). Not an error.
8101
+ * - `failed` — the provider threw; `error` carries the message.
8102
+ * - `cancelled` — the operator cancelled before this candidate was reached.
8103
+ */
8104
+ var AdoptionOutcomeSchema = _enum([
8105
+ "adopted",
8106
+ "already-adopted",
8107
+ "failed",
8108
+ "cancelled"
8109
+ ]);
8110
+ var AdoptionCandidateResultSchema = object({
8111
+ childNativeId: string(),
8112
+ outcome: AdoptionOutcomeSchema,
8113
+ /** The materialised parent device id — null for `failed` / `cancelled`. */
8114
+ parentDeviceId: number().int().nonnegative().nullable(),
8115
+ /** Accessory children created for this candidate. */
8116
+ accessoryCount: number().int().nonnegative(),
8117
+ /** Failure message; null unless `outcome === 'failed'`. */
8118
+ error: string().nullable()
8119
+ });
8120
+ var AdoptionJobSchema = object({
8121
+ jobId: string(),
8122
+ /** The integration provider this job adopts through (the `addonId` pin). */
8123
+ addonId: string(),
8124
+ integrationId: string(),
8125
+ state: AdoptionJobStateSchema,
8126
+ /** Candidates the job was asked to adopt. Known up front, so never null. */
8127
+ total: number().int().nonnegative(),
8128
+ /** Candidates that have reached a terminal bucket. */
8129
+ processed: number().int().nonnegative(),
8130
+ adopted: number().int().nonnegative(),
8131
+ alreadyAdopted: number().int().nonnegative(),
8132
+ failed: number().int().nonnegative(),
8133
+ /** Accessory child devices created across every candidate — the real unit
8134
+ * of work, surfaced so a slow job is legible rather than mysterious. */
8135
+ accessoriesCreated: number().int().nonnegative(),
8136
+ /** The candidate currently being adopted; null when idle or finished. */
8137
+ currentChildNativeId: string().nullable(),
8138
+ /** One entry per candidate, in the order they were processed. */
8139
+ results: array(AdoptionCandidateResultSchema).readonly(),
8140
+ startedAt: number(),
8141
+ finishedAt: number().nullable(),
8142
+ /** Set only when the job itself broke (not a per-candidate failure). */
8143
+ error: string().nullable()
8144
+ });
8145
+ /**
8048
8146
  * Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
8049
8147
  * pipeline functions an operator thinks in terms of.
8050
8148
  *
@@ -13213,6 +13311,15 @@ method(object({
13213
13311
  }), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
13214
13312
  kind: "mutation",
13215
13313
  auth: "admin"
13314
+ }), method(AdoptInputSchema.extend({ addonId: string() }), object({ jobId: string() }), {
13315
+ kind: "mutation",
13316
+ auth: "admin"
13317
+ }), method(object({
13318
+ addonId: string(),
13319
+ integrationId: string().optional()
13320
+ }), array(AdoptionJobSchema).readonly(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
13321
+ kind: "mutation",
13322
+ auth: "admin"
13216
13323
  }), method(ResyncInputSchema, ResyncResultSchema, {
13217
13324
  kind: "mutation",
13218
13325
  auth: "admin"
@@ -16435,6 +16542,76 @@ object({
16435
16542
  * Each provider returns a static descriptor; the core enumerates them
16436
16543
  * to validate the `integration=` query param and resolve the consent
16437
16544
  * label + the scopes baked into the issued token.
16545
+ *
16546
+ * ## Declaring one
16547
+ *
16548
+ * An OAuth client is integration-specific knowledge — who the client is, what
16549
+ * it may ask for, where it may be sent — so it is declared by the ADDON that
16550
+ * owns the integration, never by the kernel and never as a branch inside
16551
+ * `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
16552
+ * steps, no others:
16553
+ *
16554
+ * 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
16555
+ * manifest entry. This is also what tells the hub, at addon-LOAD time, that
16556
+ * a descriptor is owed — see "the boot window" below.
16557
+ * 2. Return a provider from `onInitialize()`:
16558
+ *
16559
+ * ```ts
16560
+ * const provider: IOauthIntegrationProvider = {
16561
+ * getDescriptor: async () => ({
16562
+ * integrationId: 'my-thing', // the `integration=` query param
16563
+ * displayName: 'My Thing',
16564
+ * requestedScopes: [ … ], // see below
16565
+ * allowedRedirectPrefixes: ['https://callback.example/'],
16566
+ * }),
16567
+ * }
16568
+ * return [{ capability: oauthIntegrationCapability, provider }]
16569
+ * ```
16570
+ *
16571
+ * The descriptor must be **static** — it is read on the authorize path, so
16572
+ * never put an await on network or disk behind it, and never register it
16573
+ * behind one either (a provider is registered only once `onInitialize`
16574
+ * RETURNS, so anything awaited before the return delays linking).
16575
+ * 3. Nothing else. There is no allow-list to join, no id to register with the
16576
+ * core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
16577
+ * `/api/oauth2/integrations` are built from this collection alone.
16578
+ *
16579
+ * **Scopes. `requestedScopes` has exactly ONE meaning: what the integration
16580
+ * NEEDS to function.** Not a blast radius, not a conservative
16581
+ * under-declaration, not a description of some other path the addon happens to
16582
+ * have. Derive it from what the client actually calls **with this token** —
16583
+ * every tRPC path against `METHOD_ACCESS_MAP`, plus an `addon:` grant for every
16584
+ * addon HTTP route it posts to — and write the call that justifies each entry
16585
+ * next to it. Two integrations once used this field to mean two different
16586
+ * things; the operator ruled there is one meaning, and any third integration
16587
+ * inherits it (2026-08-09).
16588
+ *
16589
+ * This is not documentation, it is the ENFORCEMENT INPUT. Since
16590
+ * [D103](../../../../docs/decisions/adr-0103.md) the `/addon/:addonId/*` gate
16591
+ * checks an integration token's grant before letting it reach an
16592
+ * `access: 'authenticated'` route, so an **under-declaration is an integration
16593
+ * that stops working** — a missing `addon:` entry means `403 Token scope
16594
+ * mismatch` on every control the client tries to actuate. Widen the descriptor
16595
+ * honestly rather than weakening a check to make a route pass.
16596
+ *
16597
+ * Prefer a narrow `capability:` scope to a `category:` one unless the client
16598
+ * genuinely needs a whole family; a category scope grants every future member
16599
+ * of that category too. `category:system [create]` has been rejected once and
16600
+ * should stay rejected: it hands `addons.installPackage` to an integration.
16601
+ *
16602
+ * Calls the ADDON itself makes over `ctx.api` run as the addon and are not
16603
+ * scope-checked, so they are not what this field describes — but reaching the
16604
+ * addon's route in the first place IS, and that is the entry to declare.
16605
+ *
16606
+ * **The boot window.** An addon registers its provider after its runner forks
16607
+ * and initialises, so between hub start and that moment this collection is
16608
+ * incomplete and an `integrationId` can be legitimately absent. The core does
16609
+ * not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
16610
+ * it compares the manifest declarers against the registered providers and
16611
+ * answers `503 temporarily_unavailable` (with `Retry-After` and the pending
16612
+ * addon ids) instead of `400 unknown integration`, and reports
16613
+ * `complete: false` on `GET /api/oauth2/integrations`. A client should retry
16614
+ * while the list is incomplete rather than conclude the hub cannot do OAuth.
16438
16615
  */
16439
16616
  var OauthIntegrationDescriptorSchema = object({
16440
16617
  /** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
@@ -16465,7 +16642,30 @@ var OauthIntegrationDescriptorSchema = object({
16465
16642
  * present, /api/oauth2/authorize bakes THIS into the code instead of the
16466
16643
  * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
16467
16644
  * the hub's env) drives the claim that its cloud Lambda routes back on. */
16468
- hubUrl: string().optional()
16645
+ hubUrl: string().optional(),
16646
+ /**
16647
+ * How long a REFRESH token issued for this integration lives — seconds, or
16648
+ * `'never'` for a token minted with no `exp` claim at all. Omit to keep the
16649
+ * 30-day default, which is what every link used before this field existed.
16650
+ *
16651
+ * Declared here for the same reason `requestedScopes` is: the integration
16652
+ * knows what it needs. Amazon's account linking and a Home Assistant config
16653
+ * entry are both meant to survive indefinitely, and re-linking is a manual
16654
+ * user action, so a 30-day expiry silently unlinks a working integration.
16655
+ *
16656
+ * **The security posture, stated so it is owned deliberately.** A refresh
16657
+ * token that never expires is permanent access if it leaks. What bounds it is
16658
+ * revocation, not time: `oauthRefresh` re-reads the session on every use and
16659
+ * returns `null` once `revokedAt` is set, as does `oauthVerifyAccessToken`.
16660
+ * The one gap is the ACCESS token — it is a plain signed JWT that nothing
16661
+ * re-checks against the session on the `/trpc` and `/addon/*` paths, so
16662
+ * revoking a link takes effect there only after its remaining hour. That hour
16663
+ * is why the access TTL is not configurable.
16664
+ *
16665
+ * The value is baked into the authorization code at `/authorize` and travels
16666
+ * on the tokens, so editing this field changes FUTURE links only.
16667
+ */
16668
+ refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
16469
16669
  });
16470
16670
  method(_void(), OauthIntegrationDescriptorSchema);
16471
16671
  /**
@@ -19787,6 +19987,37 @@ DeviceType.Camera, method(object({
19787
19987
  lastCapturedAt: number().nullable(),
19788
19988
  cacheAgeMs: number().nullable(),
19789
19989
  etag: string().nullable()
19990
+ }))), systemMethod(object({
19991
+ /** The tiles a surface is actually rendering. One entry per (device,
19992
+ * width) the caller will paint — the width is snapped to the server's
19993
+ * ladder and becomes part of the link's SIGNED identity. */
19994
+ targets: array(object({
19995
+ deviceId: number(),
19996
+ /** Target width in px. Omit for the frame as captured — correct
19997
+ * for a full-bleed surface, wrong (and expensive) for a grid. */
19998
+ width: number().int().positive().optional()
19999
+ })).min(1).max(200) }), array(object({
20000
+ deviceId: number(),
20001
+ /** Root-relative signed path, or null when the link plane is not
20002
+ * served (no data-plane facility). Present even for a device that has
20003
+ * never captured — the request is what triggers the first one (D94). */
20004
+ url: string().nullable(),
20005
+ /** Epoch ms of the frame this link serves. Null = never captured.
20006
+ * THE honest age: the tRPC path carried none before this. */
20007
+ capturedAt: number().nullable(),
20008
+ /** Age of that frame at the moment the answer was built. */
20009
+ ageMs: number().nullable(),
20010
+ /** Epoch ms after which `url` stops verifying. */
20011
+ expiresAt: number().nullable(),
20012
+ /** Ladder rung the bytes are at; null = the frame as captured. */
20013
+ width: number().nullable(),
20014
+ /** The device has never produced a frame. An empty state, not a
20015
+ * failure — and never a reason to withhold the link (D94). */
20016
+ neverCaptured: boolean(),
20017
+ /** A sleeping battery camera: the frame is deliberately stale and will
20018
+ * NOT refresh in the background. A surface should say so rather than
20019
+ * present it as current. */
20020
+ sleeping: boolean()
19790
20021
  })));
19791
20022
  /**
19792
20023
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
@@ -19832,11 +20063,29 @@ var SsoBridgeClaimsSchema = object({
19832
20063
  codeChallenge: string().optional(),
19833
20064
  /** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
19834
20065
  * tokens so the verify path can check the session is not revoked. */
19835
- sessionId: string().optional()
20066
+ sessionId: string().optional(),
20067
+ /**
20068
+ * The refresh lifetime this LINK was created with, in seconds, or `'never'`.
20069
+ * Baked into the code at `/authorize` from the integration's descriptor and
20070
+ * carried forward so `oauthRefresh` re-mints with the same lifetime. It rides
20071
+ * on the token rather than being re-read from the descriptor on purpose:
20072
+ * editing a descriptor must not retroactively extend or shorten a link the
20073
+ * operator already consented to.
20074
+ */
20075
+ refreshTtl: union([number().int().positive(), literal("never")]).optional()
19836
20076
  });
19837
20077
  method(object({
19838
20078
  claims: SsoBridgeClaimsSchema,
19839
- ttlSec: number().int().positive().optional()
20079
+ /**
20080
+ * Seconds, or `'never'` for a token minted with NO `exp` claim.
20081
+ *
20082
+ * `'never'` is a literal rather than `undefined`/`0` because omitting
20083
+ * this field already means "the 5-minute SSO hand-off default", and
20084
+ * `jwt.sign` THROWS on `{ expiresIn: undefined }` — a "no expiry" that
20085
+ * went through the numeric path would fail at mint time and break
20086
+ * linking rather than produce an eternal token.
20087
+ */
20088
+ ttlSec: union([number().int().positive(), literal("never")]).optional()
19840
20089
  }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19841
20090
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19842
20091
  providerId: string().min(1),
@@ -21632,6 +21881,37 @@ DeviceType.Light, method(object({
21632
21881
  mireds: number().int().optional(),
21633
21882
  lastChangedAt: number()
21634
21883
  });
21884
+ var ConnectionTestOutcomeSchema = discriminatedUnion("outcome", [
21885
+ object({
21886
+ outcome: literal("validated"),
21887
+ /** Round-trip of the sign-in, when the provider measured it. */
21888
+ latencyMs: number().nonnegative().optional(),
21889
+ /** Optional human detail worth showing next to the tick
21890
+ * ("3 devices visible on this account"). */
21891
+ detail: string().optional()
21892
+ }).strict(),
21893
+ object({
21894
+ outcome: literal("rejected"),
21895
+ error: string()
21896
+ }).strict(),
21897
+ object({
21898
+ outcome: literal("inconclusive"),
21899
+ error: string()
21900
+ }).strict()
21901
+ ]);
21902
+ var ConnectionTestInputSchema = object({
21903
+ /** Candidate integration settings, exactly as the create form collected them. */
21904
+ settings: record(string(), unknown()) });
21905
+ /**
21906
+ * What the provider's test actually DOES, so the UI can say it in words before
21907
+ * the operator presses the button ("Signs in to the Dreo cloud"). Purely
21908
+ * descriptive — it never changes routing.
21909
+ */
21910
+ var ConnectionTestDescriptorSchema = object({ label: string() });
21911
+ method(ConnectionTestInputSchema, ConnectionTestOutcomeSchema, {
21912
+ kind: "mutation",
21913
+ auth: "admin"
21914
+ }), method(_void(), ConnectionTestDescriptorSchema, { auth: "admin" });
21635
21915
  object({
21636
21916
  /** True when the upstream system considers the entity connected. */
21637
21917
  connected: boolean(),
@@ -22533,15 +22813,57 @@ var AvailableIntegrationTypeSchema = object({
22533
22813
  * flow can import (e.g. HA areas). Drives the adopt modal's "import
22534
22814
  * locations" checkbox. Provider-declared in the addon manifest. */
22535
22815
  supportsLocationImport: boolean(),
22816
+ /**
22817
+ * True when this integration DECLARES a pre-creation test (the
22818
+ * `connection-test` cap, or a broker whose settings it stores). Drives the
22819
+ * Test button: an integration that cannot be tested must say so up front
22820
+ * rather than offering a button that always answers the same nonsense.
22821
+ */
22822
+ canTest: boolean(),
22536
22823
  existingInstances: array(object({
22537
22824
  id: string(),
22538
22825
  name: string()
22539
22826
  })),
22540
22827
  canAdd: boolean()
22541
22828
  });
22829
+ /**
22830
+ * Why a test could not be answered as a plain boolean.
22831
+ *
22832
+ * `success` alone collapsed four different situations into one red box, and the
22833
+ * one that mattered most — "nobody ever asked the remote anything" — looked
22834
+ * exactly like "the remote said no". The status is the discriminator:
22835
+ *
22836
+ * - `validated` — a provider-declared test ran and the remote ACCEPTED.
22837
+ * - `rejected` — a provider-declared test ran and the remote REFUSED.
22838
+ * The only status that blocks `integrations.create`.
22839
+ * - `inconclusive` — a test IS declared but could not complete (timeout,
22840
+ * DNS, 5xx). Nothing was observed; not a failure.
22841
+ * - `unsupported` — this integration declares NO test. Nothing was
22842
+ * observed either; not a failure, and not a pass.
22843
+ *
22844
+ * `unsupported` and `inconclusive` both carry `success: false` so an older
22845
+ * client can never read them as a green tick, and both carry an `error` string
22846
+ * that SAYS the test did not run rather than inventing a failure.
22847
+ */
22848
+ var TestConnectionStatusEnum = _enum([
22849
+ "validated",
22850
+ "rejected",
22851
+ "inconclusive",
22852
+ "unsupported"
22853
+ ]);
22542
22854
  var TestConnectionResultSchema$1 = object({
22855
+ /** True ONLY for `validated`. Never true for a test that did not run. */
22543
22856
  success: boolean(),
22544
- error: string().optional()
22857
+ error: string().optional(),
22858
+ /** Optional for wire back-compat with clients built before the tri-state;
22859
+ * the server always sets it. */
22860
+ status: TestConnectionStatusEnum.optional(),
22861
+ /** Addon id whose declared test answered — `null` when none did. Lets the UI
22862
+ * attribute a result instead of blaming "the integration". */
22863
+ testedBy: string().nullable().optional(),
22864
+ latencyMs: number().nonnegative().optional(),
22865
+ /** Human detail from a `validated` result ("3 devices on this account"). */
22866
+ detail: string().optional()
22545
22867
  });
22546
22868
  var CreateIntegrationInputSchema = object({
22547
22869
  addonId: string(),
@@ -25694,7 +26016,12 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
25694
26016
  hubUrl: string(),
25695
26017
  /** PKCE (RFC 7636) S256 challenge. Baked into the signed code; a code
25696
26018
  * that carries one can ONLY be exchanged with the matching verifier. */
25697
- codeChallenge: string().optional()
26019
+ codeChallenge: string().optional(),
26020
+ /** The integration's declared refresh lifetime — seconds, or `'never'`.
26021
+ * From `OauthIntegrationDescriptor.refreshTokenTtlSec`. Baked into the
26022
+ * code so the link carries its own lifetime; omit for the 30-day
26023
+ * default. */
26024
+ refreshTtlSec: union([number().int().positive(), literal("never")]).optional()
25698
26025
  }), object({ code: string() }), {
25699
26026
  kind: "mutation",
25700
26027
  access: "create"
@@ -26888,6 +27215,18 @@ Object.freeze({
26888
27215
  addonId: null,
26889
27216
  access: "create"
26890
27217
  },
27218
+ "connectionTest.describeTest": {
27219
+ capName: "connection-test",
27220
+ capScope: "system",
27221
+ addonId: null,
27222
+ access: "view"
27223
+ },
27224
+ "connectionTest.testSettings": {
27225
+ capName: "connection-test",
27226
+ capScope: "system",
27227
+ addonId: null,
27228
+ access: "create"
27229
+ },
26891
27230
  "consumables.reset": {
26892
27231
  capName: "consumables",
26893
27232
  capScope: "device",
@@ -27278,6 +27617,12 @@ Object.freeze({
27278
27617
  addonId: null,
27279
27618
  access: "create"
27280
27619
  },
27620
+ "deviceManager.adoptionCancelJob": {
27621
+ capName: "device-manager",
27622
+ capScope: "system",
27623
+ addonId: null,
27624
+ access: "create"
27625
+ },
27281
27626
  "deviceManager.adoptionListCandidateFilters": {
27282
27627
  capName: "device-manager",
27283
27628
  capScope: "system",
@@ -27290,6 +27635,12 @@ Object.freeze({
27290
27635
  addonId: null,
27291
27636
  access: "view"
27292
27637
  },
27638
+ "deviceManager.adoptionListJobs": {
27639
+ capName: "device-manager",
27640
+ capScope: "system",
27641
+ addonId: null,
27642
+ access: "view"
27643
+ },
27293
27644
  "deviceManager.adoptionRefresh": {
27294
27645
  capName: "device-manager",
27295
27646
  capScope: "system",
@@ -27308,6 +27659,12 @@ Object.freeze({
27308
27659
  addonId: null,
27309
27660
  access: "create"
27310
27661
  },
27662
+ "deviceManager.adoptionStartJob": {
27663
+ capName: "device-manager",
27664
+ capScope: "system",
27665
+ addonId: null,
27666
+ access: "create"
27667
+ },
27311
27668
  "deviceManager.allocateDeviceId": {
27312
27669
  capName: "device-manager",
27313
27670
  capScope: "system",
@@ -30446,6 +30803,12 @@ Object.freeze({
30446
30803
  addonId: null,
30447
30804
  access: "view"
30448
30805
  },
30806
+ "snapshot.getSnapshotLinks": {
30807
+ capName: "snapshot",
30808
+ capScope: "device",
30809
+ addonId: null,
30810
+ access: "view"
30811
+ },
30449
30812
  "snapshot.getSnapshotOverview": {
30450
30813
  capName: "snapshot",
30451
30814
  capScope: "device",