@camstack/addon-post-analysis 1.2.56 → 1.2.59

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.
@@ -29,7 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  enumerable: true
30
30
  }) : target, mod));
31
31
  //#endregion
32
- //#region ../types/dist/event-category-41fKf-q9.mjs
32
+ //#region ../types/dist/event-category-Cv9dO26A.mjs
33
33
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
34
34
  EventCategory["SystemBoot"] = "system.boot";
35
35
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -45,6 +45,13 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
45
45
  */
46
46
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
47
47
  /**
48
+ * A newer addon or server-root package version was found by the
49
+ * authoritative registry check. Emitted once per
50
+ * `(target, packageName, currentVersion, latestVersion)` transition; repeated
51
+ * polling of the same result is deduplicated by the checker.
52
+ */
53
+ EventCategory["UpdateAvailable"] = "update.available";
54
+ /**
48
55
  * Readiness transition for a capability provider. Every producer emits
49
56
  * this event on `onInitialize` completion, `onDestroy`, and
50
57
  * `$node.reconnect`; every consumer that needs to gate on a cross-process
@@ -7316,6 +7323,104 @@ object({
7316
7323
  })
7317
7324
  });
7318
7325
  /**
7326
+ * Adoption job — the background form of `device-adoption.adopt`.
7327
+ *
7328
+ * ## Why this exists
7329
+ *
7330
+ * `adopt({childNativeIds: [...]})` materialises one CamStack device per
7331
+ * candidate PLUS every accessory child, and the whole array shares ONE UDS
7332
+ * request deadline (60s). Measured on the live hub against Home Assistant:
7333
+ * each device the kernel creates costs ~450 ms — `devices.create` pre-seeds
7334
+ * meta with up to eleven SEQUENTIAL round trips (`setName`, `setType`,
7335
+ * `setRole`, … `persistConfig`) before the class is constructed — and an
7336
+ * accessory child costs the same as its parent. So the real unit of work is
7337
+ * the CHILD, not the candidate:
7338
+ *
7339
+ * - 25 candidates averaging 6 children → ~150 devices → **>60s, times out**
7340
+ * - ONE candidate with 217 children → ~217 devices → **>60s, times out**
7341
+ *
7342
+ * That second line is why this is a job and not a smaller batch. No chunking,
7343
+ * no bounded concurrency over candidates and no per-call tuning can fix a
7344
+ * shape where **N=1 already exceeds the deadline** — the count that blows the
7345
+ * budget is the source system's accessory fan-out, which the operator does not
7346
+ * choose and cannot see. A design that only works below some N is the same bug
7347
+ * deferred.
7348
+ *
7349
+ * ## What the timeout did NOT do
7350
+ *
7351
+ * It did not stop the work. The UDS deadline ends the CALLER's wait; the
7352
+ * provider's loop runs to completion. Measured: a 25-candidate adopt that
7353
+ * "failed" at 60s had adopted 17 by 87s and all 25 by ~130s. The operator saw
7354
+ * an error and had no way to learn that. Every field below exists so that
7355
+ * question has an answer.
7356
+ *
7357
+ * ## Idempotency
7358
+ *
7359
+ * Jobs are in-RAM; a restart forgets them. That is safe here because adoption
7360
+ * is keyed by a stable id (`ha:<broker>:dev:<nativeId>` and equivalents), so
7361
+ * re-running a job re-adopts nothing: an already-adopted candidate is SKIPPED
7362
+ * by the engine before any provider call and lands in `alreadyAdopted`. It is
7363
+ * never a duplicate device, and never an error the operator has to interpret.
7364
+ */
7365
+ var AdoptionJobStateSchema = _enum([
7366
+ "running",
7367
+ "done",
7368
+ "failed",
7369
+ "cancelled"
7370
+ ]);
7371
+ /**
7372
+ * Per-candidate result. Every candidate the job was asked to adopt ends in
7373
+ * exactly one of these buckets — there is no silent drop, and the operator can
7374
+ * always answer "which of my 25 landed?".
7375
+ *
7376
+ * - `adopted` — created now by this job.
7377
+ * - `already-adopted` — a device for this candidate existed before the job
7378
+ * reached it (a re-run, or a retry after a timeout). Not an error.
7379
+ * - `failed` — the provider threw; `error` carries the message.
7380
+ * - `cancelled` — the operator cancelled before this candidate was reached.
7381
+ */
7382
+ var AdoptionOutcomeSchema = _enum([
7383
+ "adopted",
7384
+ "already-adopted",
7385
+ "failed",
7386
+ "cancelled"
7387
+ ]);
7388
+ var AdoptionCandidateResultSchema = object({
7389
+ childNativeId: string(),
7390
+ outcome: AdoptionOutcomeSchema,
7391
+ /** The materialised parent device id — null for `failed` / `cancelled`. */
7392
+ parentDeviceId: number().int().nonnegative().nullable(),
7393
+ /** Accessory children created for this candidate. */
7394
+ accessoryCount: number().int().nonnegative(),
7395
+ /** Failure message; null unless `outcome === 'failed'`. */
7396
+ error: string().nullable()
7397
+ });
7398
+ var AdoptionJobSchema = object({
7399
+ jobId: string(),
7400
+ /** The integration provider this job adopts through (the `addonId` pin). */
7401
+ addonId: string(),
7402
+ integrationId: string(),
7403
+ state: AdoptionJobStateSchema,
7404
+ /** Candidates the job was asked to adopt. Known up front, so never null. */
7405
+ total: number().int().nonnegative(),
7406
+ /** Candidates that have reached a terminal bucket. */
7407
+ processed: number().int().nonnegative(),
7408
+ adopted: number().int().nonnegative(),
7409
+ alreadyAdopted: number().int().nonnegative(),
7410
+ failed: number().int().nonnegative(),
7411
+ /** Accessory child devices created across every candidate — the real unit
7412
+ * of work, surfaced so a slow job is legible rather than mysterious. */
7413
+ accessoriesCreated: number().int().nonnegative(),
7414
+ /** The candidate currently being adopted; null when idle or finished. */
7415
+ currentChildNativeId: string().nullable(),
7416
+ /** One entry per candidate, in the order they were processed. */
7417
+ results: array(AdoptionCandidateResultSchema).readonly(),
7418
+ startedAt: number(),
7419
+ finishedAt: number().nullable(),
7420
+ /** Set only when the job itself broke (not a per-candidate failure). */
7421
+ error: string().nullable()
7422
+ });
7423
+ /**
7319
7424
  * Per-camera FUNCTION SWITCHES — the one coherent on/off surface over the
7320
7425
  * pipeline functions an operator thinks in terms of.
7321
7426
  *
@@ -12228,6 +12333,15 @@ method(object({
12228
12333
  }), method(ReleaseInputSchema.extend({ addonId: string() }), _void(), {
12229
12334
  kind: "mutation",
12230
12335
  auth: "admin"
12336
+ }), method(AdoptInputSchema.extend({ addonId: string() }), object({ jobId: string() }), {
12337
+ kind: "mutation",
12338
+ auth: "admin"
12339
+ }), method(object({
12340
+ addonId: string(),
12341
+ integrationId: string().optional()
12342
+ }), array(AdoptionJobSchema).readonly(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
12343
+ kind: "mutation",
12344
+ auth: "admin"
12231
12345
  }), method(ResyncInputSchema, ResyncResultSchema, {
12232
12346
  kind: "mutation",
12233
12347
  auth: "admin"
@@ -14180,8 +14294,35 @@ var NcDeliverySchema = _enum([
14180
14294
  "immediate",
14181
14295
  "track-end",
14182
14296
  "device-event",
14183
- "package-event"
14297
+ "package-event",
14298
+ "system-event"
14299
+ ]);
14300
+ /**
14301
+ * Stable Notification Center vocabulary over infrastructure/liveness events.
14302
+ * Bus categories are normalized into these intent-level kinds so rules do not
14303
+ * depend on a provider's raw event name or payload shape.
14304
+ */
14305
+ var NcSystemEventKindSchema = _enum([
14306
+ "camera-online",
14307
+ "camera-offline",
14308
+ "stream-online",
14309
+ "stream-offline",
14310
+ "node-online",
14311
+ "node-offline",
14312
+ "addon-update-available",
14313
+ "server-update-available"
14184
14314
  ]);
14315
+ /**
14316
+ * One coherent system-event condition. `kinds` is the required opt-in safety
14317
+ * gate; the remaining lists are optional narrowing filters relevant to the
14318
+ * selected kinds.
14319
+ */
14320
+ var NcSystemEventConditionSchema = object({
14321
+ kinds: array(NcSystemEventKindSchema).min(1),
14322
+ deviceIds: array(number().int()).min(1).optional(),
14323
+ nodeIds: array(string().min(1)).min(1).optional(),
14324
+ packageNames: array(string().min(1)).min(1).optional()
14325
+ });
14185
14326
  /** Weekly schedule — OR of windows; absence on the rule = always active. */
14186
14327
  var NcScheduleSchema = object({
14187
14328
  windows: array(object({
@@ -14486,6 +14627,8 @@ var NcConditionsSchema = object({
14486
14627
  "picked-up",
14487
14628
  "both"
14488
14629
  ]).optional(),
14630
+ /** Infrastructure/liveness/update event matcher (`system-event` delivery). */
14631
+ systemEvent: NcSystemEventConditionSchema.optional(),
14489
14632
  /**
14490
14633
  * PERSONAL-RULE custom zones (viewer-drawn). Inline normalized polygons
14491
14634
  * (MaskShape vocabulary). A record passes when its bbox overlaps ANY
@@ -14705,7 +14848,8 @@ var NcTestResultSchema = object({
14705
14848
  "object-event",
14706
14849
  "track",
14707
14850
  "device-event",
14708
- "package-event"
14851
+ "package-event",
14852
+ "system-event"
14709
14853
  ]),
14710
14854
  deviceId: number(),
14711
14855
  timestamp: number(),
@@ -14727,7 +14871,8 @@ var NcConditionDescriptorSchema = object({
14727
14871
  "schedule",
14728
14872
  "device",
14729
14873
  "package",
14730
- "occupancy"
14874
+ "occupancy",
14875
+ "system"
14731
14876
  ]),
14732
14877
  label: string(),
14733
14878
  /** Editor widget the UI renders — never hardcode per-condition forms. */
@@ -14745,7 +14890,8 @@ var NcConditionDescriptorSchema = object({
14745
14890
  "crossingSelect",
14746
14891
  "polygonDraw",
14747
14892
  "occupancy",
14748
- "deviceState"
14893
+ "deviceState",
14894
+ "systemEvent"
14749
14895
  ]),
14750
14896
  operator: _enum([
14751
14897
  "in",
@@ -14787,6 +14933,50 @@ var NcConditionDescriptorSchema = object({
14787
14933
  * rule editors render from the catalog, not hardcoded forms (spec §4.2).
14788
14934
  */
14789
14935
  var NC_CONDITION_CATALOG = [
14936
+ {
14937
+ id: "systemEvent",
14938
+ group: "system",
14939
+ label: "System event",
14940
+ valueType: "systemEvent",
14941
+ options: [
14942
+ {
14943
+ value: "camera-online",
14944
+ label: "Camera online"
14945
+ },
14946
+ {
14947
+ value: "camera-offline",
14948
+ label: "Camera offline"
14949
+ },
14950
+ {
14951
+ value: "stream-online",
14952
+ label: "Stream online"
14953
+ },
14954
+ {
14955
+ value: "stream-offline",
14956
+ label: "Stream offline"
14957
+ },
14958
+ {
14959
+ value: "node-online",
14960
+ label: "Node online"
14961
+ },
14962
+ {
14963
+ value: "node-offline",
14964
+ label: "Node offline"
14965
+ },
14966
+ {
14967
+ value: "addon-update-available",
14968
+ label: "Addon update available"
14969
+ },
14970
+ {
14971
+ value: "server-update-available",
14972
+ label: "Server update available"
14973
+ }
14974
+ ],
14975
+ operator: "in",
14976
+ appliesTo: ["system-event"],
14977
+ phase: "P1",
14978
+ description: "Infrastructure and update events. Optionally narrow camera/stream events by device, node events by node id, and addon updates by package name."
14979
+ },
14790
14980
  {
14791
14981
  id: "devices",
14792
14982
  group: "scope",
@@ -15101,7 +15291,8 @@ var NC_CONDITION_CATALOG = [
15101
15291
  "immediate",
15102
15292
  "track-end",
15103
15293
  "device-event",
15104
- "package-event"
15294
+ "package-event",
15295
+ "system-event"
15105
15296
  ],
15106
15297
  phase: "P1",
15107
15298
  description: "Weekly activation windows (invertible); absent = always active."
@@ -15129,7 +15320,8 @@ var NcHistoryRecordKindSchema = _enum([
15129
15320
  "object-event",
15130
15321
  "track-end",
15131
15322
  "device-event",
15132
- "package-event"
15323
+ "package-event",
15324
+ "system-event"
15133
15325
  ]);
15134
15326
  /** Subject summary frozen on the row at fire time (survives rule/record edits). */
15135
15327
  var NcHistorySubjectSchema = object({
@@ -15137,7 +15329,14 @@ var NcHistorySubjectSchema = object({
15137
15329
  label: string().optional(),
15138
15330
  confidence: number().optional(),
15139
15331
  zones: array(string()),
15140
- timestamp: number()
15332
+ timestamp: number(),
15333
+ systemEvent: object({
15334
+ kind: NcSystemEventKindSchema,
15335
+ subject: string(),
15336
+ title: string(),
15337
+ body: string(),
15338
+ data: record(string(), unknown())
15339
+ }).optional()
15141
15340
  });
15142
15341
  /**
15143
15342
  * One delivery-history row. This is a read-only VIEW over the durable
@@ -15600,6 +15799,76 @@ object({
15600
15799
  * Each provider returns a static descriptor; the core enumerates them
15601
15800
  * to validate the `integration=` query param and resolve the consent
15602
15801
  * label + the scopes baked into the issued token.
15802
+ *
15803
+ * ## Declaring one
15804
+ *
15805
+ * An OAuth client is integration-specific knowledge — who the client is, what
15806
+ * it may ask for, where it may be sent — so it is declared by the ADDON that
15807
+ * owns the integration, never by the kernel and never as a branch inside
15808
+ * `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
15809
+ * steps, no others:
15810
+ *
15811
+ * 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
15812
+ * manifest entry. This is also what tells the hub, at addon-LOAD time, that
15813
+ * a descriptor is owed — see "the boot window" below.
15814
+ * 2. Return a provider from `onInitialize()`:
15815
+ *
15816
+ * ```ts
15817
+ * const provider: IOauthIntegrationProvider = {
15818
+ * getDescriptor: async () => ({
15819
+ * integrationId: 'my-thing', // the `integration=` query param
15820
+ * displayName: 'My Thing',
15821
+ * requestedScopes: [ … ], // see below
15822
+ * allowedRedirectPrefixes: ['https://callback.example/'],
15823
+ * }),
15824
+ * }
15825
+ * return [{ capability: oauthIntegrationCapability, provider }]
15826
+ * ```
15827
+ *
15828
+ * The descriptor must be **static** — it is read on the authorize path, so
15829
+ * never put an await on network or disk behind it, and never register it
15830
+ * behind one either (a provider is registered only once `onInitialize`
15831
+ * RETURNS, so anything awaited before the return delays linking).
15832
+ * 3. Nothing else. There is no allow-list to join, no id to register with the
15833
+ * core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
15834
+ * `/api/oauth2/integrations` are built from this collection alone.
15835
+ *
15836
+ * **Scopes. `requestedScopes` has exactly ONE meaning: what the integration
15837
+ * NEEDS to function.** Not a blast radius, not a conservative
15838
+ * under-declaration, not a description of some other path the addon happens to
15839
+ * have. Derive it from what the client actually calls **with this token** —
15840
+ * every tRPC path against `METHOD_ACCESS_MAP`, plus an `addon:` grant for every
15841
+ * addon HTTP route it posts to — and write the call that justifies each entry
15842
+ * next to it. Two integrations once used this field to mean two different
15843
+ * things; the operator ruled there is one meaning, and any third integration
15844
+ * inherits it (2026-08-09).
15845
+ *
15846
+ * This is not documentation, it is the ENFORCEMENT INPUT. Since
15847
+ * [D103](../../../../docs/decisions/adr-0103.md) the `/addon/:addonId/*` gate
15848
+ * checks an integration token's grant before letting it reach an
15849
+ * `access: 'authenticated'` route, so an **under-declaration is an integration
15850
+ * that stops working** — a missing `addon:` entry means `403 Token scope
15851
+ * mismatch` on every control the client tries to actuate. Widen the descriptor
15852
+ * honestly rather than weakening a check to make a route pass.
15853
+ *
15854
+ * Prefer a narrow `capability:` scope to a `category:` one unless the client
15855
+ * genuinely needs a whole family; a category scope grants every future member
15856
+ * of that category too. `category:system [create]` has been rejected once and
15857
+ * should stay rejected: it hands `addons.installPackage` to an integration.
15858
+ *
15859
+ * Calls the ADDON itself makes over `ctx.api` run as the addon and are not
15860
+ * scope-checked, so they are not what this field describes — but reaching the
15861
+ * addon's route in the first place IS, and that is the entry to declare.
15862
+ *
15863
+ * **The boot window.** An addon registers its provider after its runner forks
15864
+ * and initialises, so between hub start and that moment this collection is
15865
+ * incomplete and an `integrationId` can be legitimately absent. The core does
15866
+ * not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
15867
+ * it compares the manifest declarers against the registered providers and
15868
+ * answers `503 temporarily_unavailable` (with `Retry-After` and the pending
15869
+ * addon ids) instead of `400 unknown integration`, and reports
15870
+ * `complete: false` on `GET /api/oauth2/integrations`. A client should retry
15871
+ * while the list is incomplete rather than conclude the hub cannot do OAuth.
15603
15872
  */
15604
15873
  var OauthIntegrationDescriptorSchema = object({
15605
15874
  /** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
@@ -15630,7 +15899,30 @@ var OauthIntegrationDescriptorSchema = object({
15630
15899
  * present, /api/oauth2/authorize bakes THIS into the code instead of the
15631
15900
  * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
15632
15901
  * the hub's env) drives the claim that its cloud Lambda routes back on. */
15633
- hubUrl: string().optional()
15902
+ hubUrl: string().optional(),
15903
+ /**
15904
+ * How long a REFRESH token issued for this integration lives — seconds, or
15905
+ * `'never'` for a token minted with no `exp` claim at all. Omit to keep the
15906
+ * 30-day default, which is what every link used before this field existed.
15907
+ *
15908
+ * Declared here for the same reason `requestedScopes` is: the integration
15909
+ * knows what it needs. Amazon's account linking and a Home Assistant config
15910
+ * entry are both meant to survive indefinitely, and re-linking is a manual
15911
+ * user action, so a 30-day expiry silently unlinks a working integration.
15912
+ *
15913
+ * **The security posture, stated so it is owned deliberately.** A refresh
15914
+ * token that never expires is permanent access if it leaks. What bounds it is
15915
+ * revocation, not time: `oauthRefresh` re-reads the session on every use and
15916
+ * returns `null` once `revokedAt` is set, as does `oauthVerifyAccessToken`.
15917
+ * The one gap is the ACCESS token — it is a plain signed JWT that nothing
15918
+ * re-checks against the session on the `/trpc` and `/addon/*` paths, so
15919
+ * revoking a link takes effect there only after its remaining hour. That hour
15920
+ * is why the access TTL is not configurable.
15921
+ *
15922
+ * The value is baked into the authorization code at `/authorize` and travels
15923
+ * on the tokens, so editing this field changes FUTURE links only.
15924
+ */
15925
+ refreshTokenTtlSec: union([number().int().positive(), literal("never")]).optional()
15634
15926
  });
15635
15927
  method(_void(), OauthIntegrationDescriptorSchema);
15636
15928
  /**
@@ -19188,11 +19480,29 @@ var SsoBridgeClaimsSchema = object({
19188
19480
  codeChallenge: string().optional(),
19189
19481
  /** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
19190
19482
  * tokens so the verify path can check the session is not revoked. */
19191
- sessionId: string().optional()
19483
+ sessionId: string().optional(),
19484
+ /**
19485
+ * The refresh lifetime this LINK was created with, in seconds, or `'never'`.
19486
+ * Baked into the code at `/authorize` from the integration's descriptor and
19487
+ * carried forward so `oauthRefresh` re-mints with the same lifetime. It rides
19488
+ * on the token rather than being re-read from the descriptor on purpose:
19489
+ * editing a descriptor must not retroactively extend or shorten a link the
19490
+ * operator already consented to.
19491
+ */
19492
+ refreshTtl: union([number().int().positive(), literal("never")]).optional()
19192
19493
  });
19193
19494
  method(object({
19194
19495
  claims: SsoBridgeClaimsSchema,
19195
- ttlSec: number().int().positive().optional()
19496
+ /**
19497
+ * Seconds, or `'never'` for a token minted with NO `exp` claim.
19498
+ *
19499
+ * `'never'` is a literal rather than `undefined`/`0` because omitting
19500
+ * this field already means "the 5-minute SSO hand-off default", and
19501
+ * `jwt.sign` THROWS on `{ expiresIn: undefined }` — a "no expiry" that
19502
+ * went through the numeric path would fail at mint time and break
19503
+ * linking rather than produce an eternal token.
19504
+ */
19505
+ ttlSec: union([number().int().positive(), literal("never")]).optional()
19196
19506
  }), object({ token: string() })), method(object({ token: string() }), SsoBridgeClaimsSchema.nullable());
19197
19507
  var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
19198
19508
  providerId: string().min(1),
@@ -21187,6 +21497,37 @@ onColorChanged: { data: object({
21187
21497
  */
21188
21498
  runtimeState: ColorStatusSchema
21189
21499
  };
21500
+ var ConnectionTestOutcomeSchema = discriminatedUnion("outcome", [
21501
+ object({
21502
+ outcome: literal("validated"),
21503
+ /** Round-trip of the sign-in, when the provider measured it. */
21504
+ latencyMs: number().nonnegative().optional(),
21505
+ /** Optional human detail worth showing next to the tick
21506
+ * ("3 devices visible on this account"). */
21507
+ detail: string().optional()
21508
+ }).strict(),
21509
+ object({
21510
+ outcome: literal("rejected"),
21511
+ error: string()
21512
+ }).strict(),
21513
+ object({
21514
+ outcome: literal("inconclusive"),
21515
+ error: string()
21516
+ }).strict()
21517
+ ]);
21518
+ var ConnectionTestInputSchema = object({
21519
+ /** Candidate integration settings, exactly as the create form collected them. */
21520
+ settings: record(string(), unknown()) });
21521
+ /**
21522
+ * What the provider's test actually DOES, so the UI can say it in words before
21523
+ * the operator presses the button ("Signs in to the Dreo cloud"). Purely
21524
+ * descriptive — it never changes routing.
21525
+ */
21526
+ var ConnectionTestDescriptorSchema = object({ label: string() });
21527
+ method(ConnectionTestInputSchema, ConnectionTestOutcomeSchema, {
21528
+ kind: "mutation",
21529
+ auth: "admin"
21530
+ }), method(_void(), ConnectionTestDescriptorSchema, { auth: "admin" });
21190
21531
  /**
21191
21532
  * Upstream-system connectivity sensor — distinct from `device-status`,
21192
21533
  * which is the kernel-managed online/offline flag for the device's
@@ -22574,15 +22915,57 @@ var AvailableIntegrationTypeSchema = object({
22574
22915
  * flow can import (e.g. HA areas). Drives the adopt modal's "import
22575
22916
  * locations" checkbox. Provider-declared in the addon manifest. */
22576
22917
  supportsLocationImport: boolean(),
22918
+ /**
22919
+ * True when this integration DECLARES a pre-creation test (the
22920
+ * `connection-test` cap, or a broker whose settings it stores). Drives the
22921
+ * Test button: an integration that cannot be tested must say so up front
22922
+ * rather than offering a button that always answers the same nonsense.
22923
+ */
22924
+ canTest: boolean(),
22577
22925
  existingInstances: array(object({
22578
22926
  id: string(),
22579
22927
  name: string()
22580
22928
  })),
22581
22929
  canAdd: boolean()
22582
22930
  });
22931
+ /**
22932
+ * Why a test could not be answered as a plain boolean.
22933
+ *
22934
+ * `success` alone collapsed four different situations into one red box, and the
22935
+ * one that mattered most — "nobody ever asked the remote anything" — looked
22936
+ * exactly like "the remote said no". The status is the discriminator:
22937
+ *
22938
+ * - `validated` — a provider-declared test ran and the remote ACCEPTED.
22939
+ * - `rejected` — a provider-declared test ran and the remote REFUSED.
22940
+ * The only status that blocks `integrations.create`.
22941
+ * - `inconclusive` — a test IS declared but could not complete (timeout,
22942
+ * DNS, 5xx). Nothing was observed; not a failure.
22943
+ * - `unsupported` — this integration declares NO test. Nothing was
22944
+ * observed either; not a failure, and not a pass.
22945
+ *
22946
+ * `unsupported` and `inconclusive` both carry `success: false` so an older
22947
+ * client can never read them as a green tick, and both carry an `error` string
22948
+ * that SAYS the test did not run rather than inventing a failure.
22949
+ */
22950
+ var TestConnectionStatusEnum = _enum([
22951
+ "validated",
22952
+ "rejected",
22953
+ "inconclusive",
22954
+ "unsupported"
22955
+ ]);
22583
22956
  var TestConnectionResultSchema$1 = object({
22957
+ /** True ONLY for `validated`. Never true for a test that did not run. */
22584
22958
  success: boolean(),
22585
- error: string().optional()
22959
+ error: string().optional(),
22960
+ /** Optional for wire back-compat with clients built before the tri-state;
22961
+ * the server always sets it. */
22962
+ status: TestConnectionStatusEnum.optional(),
22963
+ /** Addon id whose declared test answered — `null` when none did. Lets the UI
22964
+ * attribute a result instead of blaming "the integration". */
22965
+ testedBy: string().nullable().optional(),
22966
+ latencyMs: number().nonnegative().optional(),
22967
+ /** Human detail from a `validated` result ("3 devices on this account"). */
22968
+ detail: string().optional()
22586
22969
  });
22587
22970
  var CreateIntegrationInputSchema = object({
22588
22971
  addonId: string(),
@@ -26385,7 +26768,12 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
26385
26768
  hubUrl: string(),
26386
26769
  /** PKCE (RFC 7636) S256 challenge. Baked into the signed code; a code
26387
26770
  * that carries one can ONLY be exchanged with the matching verifier. */
26388
- codeChallenge: string().optional()
26771
+ codeChallenge: string().optional(),
26772
+ /** The integration's declared refresh lifetime — seconds, or `'never'`.
26773
+ * From `OauthIntegrationDescriptor.refreshTokenTtlSec`. Baked into the
26774
+ * code so the link carries its own lifetime; omit for the 30-day
26775
+ * default. */
26776
+ refreshTtlSec: union([number().int().positive(), literal("never")]).optional()
26389
26777
  }), object({ code: string() }), {
26390
26778
  kind: "mutation",
26391
26779
  access: "create"
@@ -28864,6 +29252,18 @@ Object.freeze({
28864
29252
  addonId: null,
28865
29253
  access: "create"
28866
29254
  },
29255
+ "connectionTest.describeTest": {
29256
+ capName: "connection-test",
29257
+ capScope: "system",
29258
+ addonId: null,
29259
+ access: "view"
29260
+ },
29261
+ "connectionTest.testSettings": {
29262
+ capName: "connection-test",
29263
+ capScope: "system",
29264
+ addonId: null,
29265
+ access: "create"
29266
+ },
28867
29267
  "consumables.reset": {
28868
29268
  capName: "consumables",
28869
29269
  capScope: "device",
@@ -29254,6 +29654,12 @@ Object.freeze({
29254
29654
  addonId: null,
29255
29655
  access: "create"
29256
29656
  },
29657
+ "deviceManager.adoptionCancelJob": {
29658
+ capName: "device-manager",
29659
+ capScope: "system",
29660
+ addonId: null,
29661
+ access: "create"
29662
+ },
29257
29663
  "deviceManager.adoptionListCandidateFilters": {
29258
29664
  capName: "device-manager",
29259
29665
  capScope: "system",
@@ -29266,6 +29672,12 @@ Object.freeze({
29266
29672
  addonId: null,
29267
29673
  access: "view"
29268
29674
  },
29675
+ "deviceManager.adoptionListJobs": {
29676
+ capName: "device-manager",
29677
+ capScope: "system",
29678
+ addonId: null,
29679
+ access: "view"
29680
+ },
29269
29681
  "deviceManager.adoptionRefresh": {
29270
29682
  capName: "device-manager",
29271
29683
  capScope: "system",
@@ -29284,6 +29696,12 @@ Object.freeze({
29284
29696
  addonId: null,
29285
29697
  access: "create"
29286
29698
  },
29699
+ "deviceManager.adoptionStartJob": {
29700
+ capName: "device-manager",
29701
+ capScope: "system",
29702
+ addonId: null,
29703
+ access: "create"
29704
+ },
29287
29705
  "deviceManager.allocateDeviceId": {
29288
29706
  capName: "device-manager",
29289
29707
  capScope: "system",
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-CcS9NwDl.js");
5
+ const require_dist = require("../dist-VrW5no7b.js");
6
6
  let node_fs = require("node:fs");
7
7
  let node_fs$1 = require_dist.__toESM(node_fs, 1);
8
8
  node_fs = require_dist.__toESM(node_fs);
@@ -13,8 +13,7 @@ require("node:crypto");
13
13
  let node_util = require("node:util");
14
14
  let node_zlib = require("node:zlib");
15
15
  let node_child_process = require("node:child_process");
16
- (0, node_util.promisify)(node_zlib.brotliCompress);
17
- (0, node_util.promisify)(node_zlib.gzip);
16
+ //#region ../system/dist/file-data-plane-CuE_hBli.mjs
18
17
  function isNonEmptyFile(filePath) {
19
18
  return node_fs$1.existsSync(filePath) && node_fs$1.statSync(filePath).size > 0;
20
19
  }
@@ -263,6 +262,8 @@ var ModelDownloadService = class {
263
262
  return files;
264
263
  }
265
264
  };
265
+ (0, node_util.promisify)(node_zlib.brotliCompress);
266
+ (0, node_util.promisify)(node_zlib.gzip);
266
267
  //#endregion
267
268
  //#region src/embedding-encoder/catalogs/embedding-models.ts
268
269
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { A as embeddingEncoderCapability, G as BaseAddon, N as hfModelUrl } from "../dist-CAC3R7XW.mjs";
1
+ import { A as embeddingEncoderCapability, G as BaseAddon, N as hfModelUrl } from "../dist-DqEv8qMO.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import "node:fs";
@@ -20,8 +20,8 @@ var __exportAll = (all, no_symbols) => {
20
20
  return target;
21
21
  };
22
22
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
23
- promisify(brotliCompress);
24
- promisify(gzip);
23
+ //#endregion
24
+ //#region ../system/dist/file-data-plane-CuE_hBli.mjs
25
25
  function isNonEmptyFile(filePath) {
26
26
  return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
27
27
  }
@@ -270,6 +270,8 @@ var ModelDownloadService = class {
270
270
  return files;
271
271
  }
272
272
  };
273
+ promisify(brotliCompress);
274
+ promisify(gzip);
273
275
  //#endregion
274
276
  //#region src/embedding-encoder/catalogs/embedding-models.ts
275
277
  var HF_REPO = "camstack/camstack-models";
@@ -1,6 +1,6 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs";
2
2
  import { t as o } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-B3Wx5J80.mjs";
3
- import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-qqYR0iVH.mjs";
3
+ import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DsSPqkLL.mjs";
4
4
  import { n as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs";
5
5
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils.js
6
6
  var _ = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), v = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), y = (e) => {