@camstack/types 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.
@@ -0,0 +1,103 @@
1
+ import { z } from 'zod';
2
+ import { type InferProvider } from './capability-definition.js';
3
+ /**
4
+ * `connection-test` — pre-creation validation of an integration's settings,
5
+ * system-scoped collection (one provider per integration addon).
6
+ *
7
+ * ── Why this cap exists ─────────────────────────────────────────────────────
8
+ *
9
+ * Before it, `integrations.testConnection` had exactly two behaviours: a broker
10
+ * branch (`settings.brokerId` → `broker.testConnection`) and a DEFAULT branch
11
+ * that probed `settings.main_stream_url ?? settings.url` with ffprobe. Every
12
+ * account-based integration — Dreo, Dreame, Tuya, Petkit, Wyze — fell into that
13
+ * default and was told `{"success":false,"error":"No stream URL provided"}`.
14
+ * That answer neither validated nor refused anything, so:
15
+ *
16
+ * - the Test button had NEVER worked for an account integration, and
17
+ * - `integrations.create` had nothing to gate on, so an integration with a
18
+ * wrong password was created happily and failed later, silently, at
19
+ * reconcile time.
20
+ *
21
+ * The structural gap was that at CREATE time the integration does not exist
22
+ * yet: there is no `integrationId`, no `brokerId`, no live client — and every
23
+ * existing provider surface (`device-provider`, `device-adoption`) is keyed by
24
+ * one of those. There was no way to ask "are these settings valid?" before the
25
+ * row existed.
26
+ *
27
+ * ── The contract ────────────────────────────────────────────────────────────
28
+ *
29
+ * The provider knows how to validate its OWN settings. The framework does not
30
+ * guess from the shape of the settings — a stream-URL probe is one provider's
31
+ * implementation of this cap, not the universal fallback. A provider that does
32
+ * not register this cap is a KNOWN "cannot validate", never a silent pass.
33
+ *
34
+ * `testSettings` takes the candidate settings blob exactly as the wizard's
35
+ * config step collected it (the same blob that would be handed to
36
+ * `integrations.create`), and MUST NOT persist anything, mint an integration,
37
+ * or mutate live state. It opens a throwaway session, asks, and closes it.
38
+ *
39
+ * ── The three outcomes are NOT interchangeable ──────────────────────────────
40
+ *
41
+ * This is the whole point of the discriminated union: a `null` from a timeout
42
+ * must never look like a `null` from a refusal.
43
+ *
44
+ * - `validated` — the remote ACCEPTED these credentials. Observed.
45
+ * - `rejected` — the remote REFUSED these credentials. Observed.
46
+ * This is the ONLY outcome that blocks creation.
47
+ * - `inconclusive` — the check could not complete (DNS, timeout, 5xx, an
48
+ * unexpected shape). NOTHING was observed about the
49
+ * credentials. Never rendered, or counted, as a failure.
50
+ *
51
+ * A provider that cannot tell a refusal from a transport fault must return
52
+ * `inconclusive`. Guessing `rejected` would block creation on a flaky network;
53
+ * guessing `validated` would wave a wrong password through.
54
+ */
55
+ /** Ceiling on how long a pre-creation probe may hold the wizard. */
56
+ export declare const CONNECTION_TEST_TIMEOUT_MS = 20000;
57
+ export declare const ConnectionTestOutcomeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
58
+ outcome: z.ZodLiteral<"validated">;
59
+ latencyMs: z.ZodOptional<z.ZodNumber>;
60
+ detail: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strict>, z.ZodObject<{
62
+ outcome: z.ZodLiteral<"rejected">;
63
+ error: z.ZodString;
64
+ }, z.core.$strict>, z.ZodObject<{
65
+ outcome: z.ZodLiteral<"inconclusive">;
66
+ error: z.ZodString;
67
+ }, z.core.$strict>], "outcome">;
68
+ export type ConnectionTestOutcome = z.infer<typeof ConnectionTestOutcomeSchema>;
69
+ export declare const ConnectionTestInputSchema: z.ZodObject<{
70
+ settings: z.ZodRecord<z.ZodString, z.ZodUnknown>;
71
+ }, z.core.$strip>;
72
+ /**
73
+ * What the provider's test actually DOES, so the UI can say it in words before
74
+ * the operator presses the button ("Signs in to the Dreo cloud"). Purely
75
+ * descriptive — it never changes routing.
76
+ */
77
+ export declare const ConnectionTestDescriptorSchema: z.ZodObject<{
78
+ label: z.ZodString;
79
+ }, z.core.$strip>;
80
+ export declare const connectionTestCapability: {
81
+ readonly name: "connection-test";
82
+ readonly scope: "system";
83
+ readonly mode: "collection";
84
+ readonly methods: {
85
+ readonly testSettings: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
86
+ settings: z.ZodRecord<z.ZodString, z.ZodUnknown>;
87
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
88
+ outcome: z.ZodLiteral<"validated">;
89
+ latencyMs: z.ZodOptional<z.ZodNumber>;
90
+ detail: z.ZodOptional<z.ZodString>;
91
+ }, z.core.$strict>, z.ZodObject<{
92
+ outcome: z.ZodLiteral<"rejected">;
93
+ error: z.ZodString;
94
+ }, z.core.$strict>, z.ZodObject<{
95
+ outcome: z.ZodLiteral<"inconclusive">;
96
+ error: z.ZodString;
97
+ }, z.core.$strict>], "outcome">, "mutation">;
98
+ readonly describeTest: import("./capability-definition.js").CapabilityMethodSchema<z.ZodVoid, z.ZodObject<{
99
+ label: z.ZodString;
100
+ }, z.core.$strip>, import("./capability-definition.js").CapabilityMethodKind>;
101
+ };
102
+ };
103
+ export type IConnectionTestProvider = InferProvider<typeof connectionTestCapability>;
@@ -1159,6 +1159,73 @@ export declare const deviceManagerCapability: {
1159
1159
  camDeviceId: z.ZodNumber;
1160
1160
  addonId: z.ZodString;
1161
1161
  }, z.core.$strip>, z.ZodVoid, "mutation">;
1162
+ /**
1163
+ * Start a background adoption and return its `jobId` immediately. The job
1164
+ * adopts ONE candidate per provider call, so no single request can exceed
1165
+ * the transport deadline, and it skips candidates that are already adopted
1166
+ * — which makes re-submitting a batch after a timeout safe and silent
1167
+ * rather than a wall of duplicate-stableId errors.
1168
+ */
1169
+ readonly adoptionStartJob: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1170
+ integrationId: z.ZodString;
1171
+ childNativeIds: z.ZodArray<z.ZodString>;
1172
+ filter: z.ZodOptional<z.ZodString>;
1173
+ importLocations: z.ZodOptional<z.ZodBoolean>;
1174
+ perCandidate: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1175
+ name: z.ZodOptional<z.ZodString>;
1176
+ hiddenChildIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
1177
+ }, z.core.$strip>>>;
1178
+ addonId: z.ZodString;
1179
+ }, z.core.$strip>, z.ZodObject<{
1180
+ jobId: z.ZodString;
1181
+ }, z.core.$strip>, "mutation">;
1182
+ /**
1183
+ * Adoption jobs for an integration, newest first. This is the answer to
1184
+ * "which of my 25 landed?" — `results` carries one entry per candidate,
1185
+ * every one of them in a named bucket.
1186
+ */
1187
+ readonly adoptionListJobs: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1188
+ addonId: z.ZodString;
1189
+ integrationId: z.ZodOptional<z.ZodString>;
1190
+ }, z.core.$strip>, z.ZodReadonly<z.ZodArray<z.ZodObject<{
1191
+ jobId: z.ZodString;
1192
+ addonId: z.ZodString;
1193
+ integrationId: z.ZodString;
1194
+ state: z.ZodEnum<{
1195
+ done: "done";
1196
+ failed: "failed";
1197
+ running: "running";
1198
+ cancelled: "cancelled";
1199
+ }>;
1200
+ total: z.ZodNumber;
1201
+ processed: z.ZodNumber;
1202
+ adopted: z.ZodNumber;
1203
+ alreadyAdopted: z.ZodNumber;
1204
+ failed: z.ZodNumber;
1205
+ accessoriesCreated: z.ZodNumber;
1206
+ currentChildNativeId: z.ZodNullable<z.ZodString>;
1207
+ results: z.ZodReadonly<z.ZodArray<z.ZodObject<{
1208
+ childNativeId: z.ZodString;
1209
+ outcome: z.ZodEnum<{
1210
+ failed: "failed";
1211
+ cancelled: "cancelled";
1212
+ adopted: "adopted";
1213
+ "already-adopted": "already-adopted";
1214
+ }>;
1215
+ parentDeviceId: z.ZodNullable<z.ZodNumber>;
1216
+ accessoryCount: z.ZodNumber;
1217
+ error: z.ZodNullable<z.ZodString>;
1218
+ }, z.core.$strip>>>;
1219
+ startedAt: z.ZodNumber;
1220
+ finishedAt: z.ZodNullable<z.ZodNumber>;
1221
+ error: z.ZodNullable<z.ZodString>;
1222
+ }, z.core.$strip>>>, import("./capability-definition.js").CapabilityMethodKind>;
1223
+ /** Cooperative cancel: the in-flight candidate finishes, the rest never start. */
1224
+ readonly adoptionCancelJob: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
1225
+ jobId: z.ZodString;
1226
+ }, z.core.$strip>, z.ZodObject<{
1227
+ cancelled: z.ZodBoolean;
1228
+ }, z.core.$strip>, "mutation">;
1162
1229
  /**
1163
1230
  * Re-sync a device with its source via the device-adoption provider of the
1164
1231
  * device's OWNING addon (resolved from `camDeviceId`). Unlike the singleton
@@ -127,6 +127,7 @@ export { type CameraCredentials, CameraCredentialsSchema, type CameraCredentials
127
127
  export { type CarbonMonoxideStatus, CarbonMonoxideStatusSchema, carbonMonoxideCapability, type ICarbonMonoxideProvider, } from './carbon-monoxide.cap.js';
128
128
  export { type ClimateControlStatus, ClimateControlStatusSchema, climateControlCapability, type HvacMode, HvacModeSchema, type IClimateControlProvider, } from './climate-control.cap.js';
129
129
  export { type ColorHsvTriplet, type ColorInput, type ColorRgbTriplet, type ColorStatus, ColorStatusSchema, colorCapability, type IColorProvider, } from './color.cap.js';
130
+ export { CONNECTION_TEST_TIMEOUT_MS, ConnectionTestDescriptorSchema, ConnectionTestInputSchema, type ConnectionTestOutcome, ConnectionTestOutcomeSchema, connectionTestCapability, type IConnectionTestProvider, } from './connection-test.cap.js';
130
131
  export { type ConnectivityStatus, ConnectivityStatusSchema, connectivityCapability, type IConnectivityProvider, } from './connectivity.cap.js';
131
132
  export { type ConsumableItem, ConsumableItemSchema, type ConsumablesStatus, ConsumablesStatusSchema, consumablesCapability, type IConsumablesProvider, } from './consumables.cap.js';
132
133
  export { type ContactStatus, ContactStatusSchema, contactCapability, type IContactProvider, } from './contact.cap.js';
@@ -149,7 +150,7 @@ export { type HumidifierStatus, HumidifierStatusSchema, humidifierCapability, ty
149
150
  export { type HumiditySensorStatus, HumiditySensorStatusSchema, humiditySensorCapability, type IHumiditySensorProvider, } from './humidity-sensor.cap.js';
150
151
  export { type IImageProvider, type ImageStatus, ImageStatusSchema, imageCapability, } from './image.cap.js';
151
152
  export { type BacklightMode, BacklightModeSchema, type ExposureMode, ExposureModeSchema, type IImageSettingsProvider, type ImageRotate, ImageRotateSchema, type ImageSettingsOptions, ImageSettingsOptionsSchema, type ImageSettingsPatch, ImageSettingsPatchSchema, type ImageSettingsStatus, ImageSettingsStatusSchema, imageSettingsCapability, type WhiteBalanceMode, WhiteBalanceModeSchema, } from './image-settings.cap.js';
152
- export { AvailableIntegrationTypeSchema, CreateIntegrationInputSchema, DeleteIntegrationResultSchema, type IIntegrationsProvider, IntegrationLiteSchema, IntegrationWithStateSchema, integrationsCapability, TestConnectionResultSchema, UpdateIntegrationInputSchema, } from './integrations.cap.js';
153
+ export { AvailableIntegrationTypeSchema, CreateIntegrationInputSchema, DeleteIntegrationResultSchema, type IIntegrationsProvider, IntegrationLiteSchema, type IntegrationTestConnectionResult, type IntegrationTestConnectionStatus, IntegrationWithStateSchema, integrationsCapability, TestConnectionResultSchema, TestConnectionStatusEnum, UpdateIntegrationInputSchema, } from './integrations.cap.js';
153
154
  export { type IIntercomProvider, type IntercomAbility, IntercomAbilitySchema, type IntercomStatus, IntercomStatusSchema, intercomCapability, } from './intercom.cap.js';
154
155
  export { type DeviceCodeSeverity, DeviceCodeSeveritySchema, type ILawnMowerControlProvider, type LawnMowerActivity, LawnMowerActivitySchema, type LawnMowerControlStatus, LawnMowerControlStatusSchema, lawnMowerControlCapability, } from './lawn-mower-control.cap.js';
155
156
  export { type ConnectionEndpoint, type ILocalNetworkProvider, type LocalInterface, localNetworkCapability, } from './local-network.cap.js';
@@ -233,6 +234,7 @@ import type { cameraStreamsCapability } from './camera-streams.cap.js';
233
234
  import type { carbonMonoxideCapability } from './carbon-monoxide.cap.js';
234
235
  import type { climateControlCapability } from './climate-control.cap.js';
235
236
  import type { colorCapability } from './color.cap.js';
237
+ import type { connectionTestCapability } from './connection-test.cap.js';
236
238
  import type { connectivityCapability } from './connectivity.cap.js';
237
239
  import type { consumablesCapability } from './consumables.cap.js';
238
240
  import type { contactCapability } from './contact.cap.js';
@@ -349,6 +351,6 @@ import type { webrtcSessionCapability } from './webrtc-session.cap.js';
349
351
  import type { zoneAnalyticsCapability } from './zone-analytics.cap.js';
350
352
  import type { zoneRulesCapability } from './zone-rules.cap.js';
351
353
  import type { zonesCapability } from './zones.cap.js';
352
- type AnyCapability = typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof terminalSessionCapability | typeof settingsStoreCapability | typeof dataStoreProviderCapability | typeof logDestinationCapability | typeof adminUiCapability | typeof viewerUiCapability | typeof ssoBridgeCapability | typeof userPasskeysCapability | typeof smtpProviderCapability | typeof mqttBrokerCapability | typeof brokerCapability | typeof deviceAdoptionCapability | typeof deviceExportCapability | typeof addonPagesCapability | typeof addonPagesSourceCapability | typeof addonWidgetsCapability | typeof addonWidgetsSourceCapability | typeof customModelRegistryCapability | typeof modelDistributorCapability | typeof modelConvertCapability | typeof addonRoutesCapability | typeof streamBrokerCapability | typeof decoderCapability | typeof webrtcSessionCapability | typeof cameraStreamsCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof vectorStoreCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof loginMethodCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof llmCapability | typeof llmRuntimeCapability | typeof notificationOutputCapability | typeof coreBlocksCapability | typeof notificationRulesCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof consumablesCapability | typeof rebootCapability | typeof deviceDiscoveryCapability | typeof brightnessCapability | typeof colorCapability | typeof climateControlCapability | typeof coverCapability | typeof valveCapability | typeof humidifierCapability | typeof waterHeaterCapability | typeof weatherCapability | typeof imageCapability | typeof lockControlCapability | typeof vacuumControlCapability | typeof petFeederCapability | typeof lawnMowerControlCapability | typeof fanControlCapability | typeof controlCapability | typeof notifierCapability | typeof mediaPlayerCapability | typeof alarmPanelCapability | typeof presenceCapability | typeof scriptRunnerCapability | typeof automationControlCapability | typeof motionTriggerCapability | typeof eventsCapability | typeof zonesCapability | typeof zoneRulesCapability | typeof zoneAnalyticsCapability | typeof audioMetricsCapability | typeof motionCapability | typeof contactCapability | typeof floodCapability | typeof smokeCapability | typeof carbonMonoxideCapability | typeof gasCapability | typeof tamperCapability | typeof vibrationCapability | typeof connectivityCapability | typeof binaryCapability | typeof temperatureSensorCapability | typeof humiditySensorCapability | typeof ambientLightSensorCapability | typeof pressureSensorCapability | typeof powerMeterCapability | typeof airQualitySensorCapability | typeof numericSensorCapability | typeof enumSensorCapability | typeof recordingCapability | typeof recordingExportCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof serverManagementCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof sceneMonitorCapability | typeof privacyMaskCapability | typeof dayNightCapability | typeof imageSettingsCapability | typeof osdCapability | typeof osdManagerCapability | typeof accessoriesCapability | typeof batteryCapability | typeof buttonCapability | typeof cameraCredentialsCapability | typeof deviceStatusCapability | typeof doorbellCapability | typeof eventEmitterCapability | typeof faceGalleryCapability | typeof featureProbeCapability | typeof intercomCapability | typeof nativeObjectDetectionCapability | typeof plateGalleryCapability | typeof switchCapability | typeof updateCapability | typeof videoclipsCapability;
354
+ type AnyCapability = typeof addonSettingsCapability | typeof alertsCapability | typeof storageCapability | typeof storageProviderCapability | typeof storageEvictableCapability | typeof filesystemBrowseCapability | typeof backupCapability | typeof terminalSessionCapability | typeof settingsStoreCapability | typeof dataStoreProviderCapability | typeof logDestinationCapability | typeof adminUiCapability | typeof viewerUiCapability | typeof ssoBridgeCapability | typeof userPasskeysCapability | typeof smtpProviderCapability | typeof mqttBrokerCapability | typeof brokerCapability | typeof deviceAdoptionCapability | typeof deviceExportCapability | typeof addonPagesCapability | typeof addonPagesSourceCapability | typeof addonWidgetsCapability | typeof addonWidgetsSourceCapability | typeof customModelRegistryCapability | typeof modelDistributorCapability | typeof modelConvertCapability | typeof addonRoutesCapability | typeof streamBrokerCapability | typeof decoderCapability | typeof webrtcSessionCapability | typeof cameraStreamsCapability | typeof motionDetectionCapability | typeof pipelineExecutorCapability | typeof detectionPipelineCapability | typeof cameraPipelineConfigCapability | typeof pipelineRunnerCapability | typeof pipelineOrchestratorCapability | typeof audioAnalyzerCapability | typeof audioAnalysisCapability | typeof audioCodecCapability | typeof embeddingEncoderCapability | typeof vectorStoreCapability | typeof deviceProviderCapability | typeof deviceManagerCapability | typeof deviceStateCapability | typeof authProviderCapability | typeof loginMethodCapability | typeof networkAccessCapability | typeof turnProviderCapability | typeof snapshotCapability | typeof llmCapability | typeof llmRuntimeCapability | typeof notificationOutputCapability | typeof coreBlocksCapability | typeof notificationRulesCapability | typeof pipelineAnalyticsCapability | typeof metricsProviderCapability | typeof ptzCapability | typeof ptzAutotrackCapability | typeof consumablesCapability | typeof connectionTestCapability | typeof rebootCapability | typeof deviceDiscoveryCapability | typeof brightnessCapability | typeof colorCapability | typeof climateControlCapability | typeof coverCapability | typeof valveCapability | typeof humidifierCapability | typeof waterHeaterCapability | typeof weatherCapability | typeof imageCapability | typeof lockControlCapability | typeof vacuumControlCapability | typeof petFeederCapability | typeof lawnMowerControlCapability | typeof fanControlCapability | typeof controlCapability | typeof notifierCapability | typeof mediaPlayerCapability | typeof alarmPanelCapability | typeof presenceCapability | typeof scriptRunnerCapability | typeof automationControlCapability | typeof motionTriggerCapability | typeof eventsCapability | typeof zonesCapability | typeof zoneRulesCapability | typeof zoneAnalyticsCapability | typeof audioMetricsCapability | typeof motionCapability | typeof contactCapability | typeof floodCapability | typeof smokeCapability | typeof carbonMonoxideCapability | typeof gasCapability | typeof tamperCapability | typeof vibrationCapability | typeof connectivityCapability | typeof binaryCapability | typeof temperatureSensorCapability | typeof humiditySensorCapability | typeof ambientLightSensorCapability | typeof pressureSensorCapability | typeof powerMeterCapability | typeof airQualitySensorCapability | typeof numericSensorCapability | typeof enumSensorCapability | typeof recordingCapability | typeof recordingExportCapability | typeof deviceOpsCapability | typeof platformProbeCapability | typeof localNetworkCapability | typeof meshNetworkCapability | typeof userManagementCapability | typeof systemCapability | typeof networkQualityCapability | typeof toastCapability | typeof nodesCapability | typeof serverManagementCapability | typeof integrationsCapability | typeof addonsCapability | typeof oauthIntegrationCapability | typeof streamParamsCapability | typeof streamCatalogCapability | typeof motionZonesCapability | typeof sceneMonitorCapability | typeof privacyMaskCapability | typeof dayNightCapability | typeof imageSettingsCapability | typeof osdCapability | typeof osdManagerCapability | typeof accessoriesCapability | typeof batteryCapability | typeof buttonCapability | typeof cameraCredentialsCapability | typeof deviceStatusCapability | typeof doorbellCapability | typeof eventEmitterCapability | typeof faceGalleryCapability | typeof featureProbeCapability | typeof intercomCapability | typeof nativeObjectDetectionCapability | typeof plateGalleryCapability | typeof switchCapability | typeof updateCapability | typeof videoclipsCapability;
353
355
  export type CapabilityName = AnyCapability['name'];
354
356
  export type ITypedReadinessRegistry = IReadinessRegistry<CapabilityName>;
@@ -54,15 +54,50 @@ declare const AvailableIntegrationTypeSchema: z.ZodObject<{
54
54
  }>;
55
55
  brokerKind: z.ZodNullable<z.ZodString>;
56
56
  supportsLocationImport: z.ZodBoolean;
57
+ canTest: z.ZodBoolean;
57
58
  existingInstances: z.ZodArray<z.ZodObject<{
58
59
  id: z.ZodString;
59
60
  name: z.ZodString;
60
61
  }, z.core.$strip>>;
61
62
  canAdd: z.ZodBoolean;
62
63
  }, z.core.$strip>;
64
+ /**
65
+ * Why a test could not be answered as a plain boolean.
66
+ *
67
+ * `success` alone collapsed four different situations into one red box, and the
68
+ * one that mattered most — "nobody ever asked the remote anything" — looked
69
+ * exactly like "the remote said no". The status is the discriminator:
70
+ *
71
+ * - `validated` — a provider-declared test ran and the remote ACCEPTED.
72
+ * - `rejected` — a provider-declared test ran and the remote REFUSED.
73
+ * The only status that blocks `integrations.create`.
74
+ * - `inconclusive` — a test IS declared but could not complete (timeout,
75
+ * DNS, 5xx). Nothing was observed; not a failure.
76
+ * - `unsupported` — this integration declares NO test. Nothing was
77
+ * observed either; not a failure, and not a pass.
78
+ *
79
+ * `unsupported` and `inconclusive` both carry `success: false` so an older
80
+ * client can never read them as a green tick, and both carry an `error` string
81
+ * that SAYS the test did not run rather than inventing a failure.
82
+ */
83
+ declare const TestConnectionStatusEnum: z.ZodEnum<{
84
+ validated: "validated";
85
+ rejected: "rejected";
86
+ inconclusive: "inconclusive";
87
+ unsupported: "unsupported";
88
+ }>;
63
89
  declare const TestConnectionResultSchema: z.ZodObject<{
64
90
  success: z.ZodBoolean;
65
91
  error: z.ZodOptional<z.ZodString>;
92
+ status: z.ZodOptional<z.ZodEnum<{
93
+ validated: "validated";
94
+ rejected: "rejected";
95
+ inconclusive: "inconclusive";
96
+ unsupported: "unsupported";
97
+ }>>;
98
+ testedBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
99
+ latencyMs: z.ZodOptional<z.ZodNumber>;
100
+ detail: z.ZodOptional<z.ZodString>;
66
101
  }, z.core.$strip>;
67
102
  declare const CreateIntegrationInputSchema: z.ZodObject<{
68
103
  addonId: z.ZodString;
@@ -184,6 +219,7 @@ export declare const integrationsCapability: {
184
219
  }>;
185
220
  brokerKind: z.ZodNullable<z.ZodString>;
186
221
  supportsLocationImport: z.ZodBoolean;
222
+ canTest: z.ZodBoolean;
187
223
  existingInstances: z.ZodArray<z.ZodObject<{
188
224
  id: z.ZodString;
189
225
  name: z.ZodString;
@@ -196,6 +232,15 @@ export declare const integrationsCapability: {
196
232
  }, z.core.$strip>, z.ZodObject<{
197
233
  success: z.ZodBoolean;
198
234
  error: z.ZodOptional<z.ZodString>;
235
+ status: z.ZodOptional<z.ZodEnum<{
236
+ validated: "validated";
237
+ rejected: "rejected";
238
+ inconclusive: "inconclusive";
239
+ unsupported: "unsupported";
240
+ }>>;
241
+ testedBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
242
+ latencyMs: z.ZodOptional<z.ZodNumber>;
243
+ detail: z.ZodOptional<z.ZodString>;
199
244
  }, z.core.$strip>, "mutation">;
200
245
  };
201
246
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
@@ -204,4 +249,6 @@ export declare const integrationsCapability: {
204
249
  };
205
250
  };
206
251
  export type IIntegrationsProvider = InferProvider<typeof integrationsCapability>;
207
- export { IntegrationWithStateSchema, IntegrationLiteSchema, AvailableIntegrationTypeSchema, TestConnectionResultSchema, CreateIntegrationInputSchema, UpdateIntegrationInputSchema, DeleteIntegrationResultSchema, };
252
+ export type IntegrationTestConnectionStatus = z.infer<typeof TestConnectionStatusEnum>;
253
+ export type IntegrationTestConnectionResult = z.infer<typeof TestConnectionResultSchema>;
254
+ export { AvailableIntegrationTypeSchema, CreateIntegrationInputSchema, DeleteIntegrationResultSchema, IntegrationLiteSchema, IntegrationWithStateSchema, TestConnectionResultSchema, TestConnectionStatusEnum, UpdateIntegrationInputSchema, };
@@ -6,6 +6,65 @@ import { type InferProvider } from './capability-definition.js';
6
6
  * Each provider returns a static descriptor; the core enumerates them
7
7
  * to validate the `integration=` query param and resolve the consent
8
8
  * label + the scopes baked into the issued token.
9
+ *
10
+ * ## Declaring one
11
+ *
12
+ * An OAuth client is integration-specific knowledge — who the client is, what
13
+ * it may ask for, where it may be sent — so it is declared by the ADDON that
14
+ * owns the integration, never by the kernel and never as a branch inside
15
+ * `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
16
+ * steps, no others:
17
+ *
18
+ * 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
19
+ * manifest entry. This is also what tells the hub, at addon-LOAD time, that
20
+ * a descriptor is owed — see "the boot window" below.
21
+ * 2. Return a provider from `onInitialize()`:
22
+ *
23
+ * ```ts
24
+ * const provider: IOauthIntegrationProvider = {
25
+ * getDescriptor: async () => ({
26
+ * integrationId: 'my-thing', // the `integration=` query param
27
+ * displayName: 'My Thing',
28
+ * requestedScopes: [ … ], // see below
29
+ * allowedRedirectPrefixes: ['https://callback.example/'],
30
+ * }),
31
+ * }
32
+ * return [{ capability: oauthIntegrationCapability, provider }]
33
+ * ```
34
+ *
35
+ * The descriptor must be **static** — it is read on the authorize path, so
36
+ * never put an await on network or disk behind it, and never register it
37
+ * behind one either (a provider is registered only once `onInitialize`
38
+ * RETURNS, so anything awaited before the return delays linking).
39
+ * 3. Nothing else. There is no allow-list to join, no id to register with the
40
+ * core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
41
+ * `/api/oauth2/integrations` are built from this collection alone.
42
+ *
43
+ * **Scopes.** `requestedScopes` is baked into every token this integration is
44
+ * ever issued and the operator consents to it once. Derive it from the tRPC
45
+ * paths the client calls **with that token**, against `METHOD_ACCESS_MAP`, and
46
+ * prefer a narrow `capability:` scope to a `category:` one unless the client
47
+ * genuinely needs a whole family. A category scope grants every future member
48
+ * of that category too. `category:system [create]` has been rejected once and
49
+ * should stay rejected: it hands `addons.installPackage` to an integration.
50
+ *
51
+ * What it does NOT cover: calls the ADDON makes over `ctx.api`, which run as
52
+ * the addon and are not scope-checked. Alexa's descriptor is narrower than
53
+ * Home Assistant's for exactly that reason — its Lambda posts directives and
54
+ * the addon does the work, while the Home Assistant component calls tRPC
55
+ * directly with the token. So `requestedScopes` describes the blast radius of
56
+ * the GRANT, not the reach of the integration; do not widen one to describe the
57
+ * other.
58
+ *
59
+ * **The boot window.** An addon registers its provider after its runner forks
60
+ * and initialises, so between hub start and that moment this collection is
61
+ * incomplete and an `integrationId` can be legitimately absent. The core does
62
+ * not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
63
+ * it compares the manifest declarers against the registered providers and
64
+ * answers `503 temporarily_unavailable` (with `Retry-After` and the pending
65
+ * addon ids) instead of `400 unknown integration`, and reports
66
+ * `complete: false` on `GET /api/oauth2/integrations`. A client should retry
67
+ * while the list is incomplete rather than conclude the hub cannot do OAuth.
9
68
  */
10
69
  declare const OauthIntegrationDescriptorSchema: z.ZodObject<{
11
70
  integrationId: z.ZodString;
@@ -26,6 +26,7 @@ import type { cameraCredentialsCapability } from '../capabilities/camera-credent
26
26
  import type { cameraStreamsCapability } from '../capabilities/camera-streams.cap.js';
27
27
  import type { climateControlCapability } from '../capabilities/climate-control.cap.js';
28
28
  import type { colorCapability } from '../capabilities/color.cap.js';
29
+ import type { connectionTestCapability } from '../capabilities/connection-test.cap.js';
29
30
  import type { consumablesCapability } from '../capabilities/consumables.cap.js';
30
31
  import type { controlCapability } from '../capabilities/control.cap.js';
31
32
  import type { coreBlocksCapability } from '../capabilities/core-blocks.cap.js';
@@ -1323,6 +1324,28 @@ export type AppRouter = TrpcCoreRouter<{
1323
1324
  meta: object;
1324
1325
  }>;
1325
1326
  }>>;
1327
+ connectionTest: TRPCBuiltRouter<{
1328
+ ctx: TrpcContext;
1329
+ meta: object;
1330
+ errorShape: AugmentedErrorShape;
1331
+ transformer: true;
1332
+ }, TRPCDecorateCreateRouterOptions<{
1333
+ testSettings: TRPCMutationProcedure<{
1334
+ input: {
1335
+ [x: string]: unknown;
1336
+ } & z.input<typeof connectionTestCapability.methods.testSettings.input>;
1337
+ output: z.infer<typeof connectionTestCapability.methods.testSettings.output>;
1338
+ meta: object;
1339
+ }>;
1340
+ describeTest: TRPCQueryProcedure<{
1341
+ input: {
1342
+ nodeId?: string | undefined;
1343
+ addonId?: string | undefined;
1344
+ } | undefined;
1345
+ output: z.infer<typeof connectionTestCapability.methods.describeTest.output>;
1346
+ meta: object;
1347
+ }>;
1348
+ }>>;
1326
1349
  connectivity: TRPCBuiltRouter<{
1327
1350
  ctx: TrpcContext;
1328
1351
  meta: object;
@@ -2419,6 +2442,27 @@ export type AppRouter = TrpcCoreRouter<{
2419
2442
  output: z.infer<typeof deviceManagerCapability.methods.adoptionRelease.output>;
2420
2443
  meta: object;
2421
2444
  }>;
2445
+ adoptionStartJob: TRPCMutationProcedure<{
2446
+ input: {
2447
+ [x: string]: unknown;
2448
+ } & z.input<typeof deviceManagerCapability.methods.adoptionStartJob.input>;
2449
+ output: z.infer<typeof deviceManagerCapability.methods.adoptionStartJob.output>;
2450
+ meta: object;
2451
+ }>;
2452
+ adoptionListJobs: TRPCQueryProcedure<{
2453
+ input: {
2454
+ [x: string]: unknown;
2455
+ } & z.input<typeof deviceManagerCapability.methods.adoptionListJobs.input>;
2456
+ output: z.infer<typeof deviceManagerCapability.methods.adoptionListJobs.output>;
2457
+ meta: object;
2458
+ }>;
2459
+ adoptionCancelJob: TRPCMutationProcedure<{
2460
+ input: {
2461
+ [x: string]: unknown;
2462
+ } & z.input<typeof deviceManagerCapability.methods.adoptionCancelJob.input>;
2463
+ output: z.infer<typeof deviceManagerCapability.methods.adoptionCancelJob.output>;
2464
+ meta: object;
2465
+ }>;
2422
2466
  adoptionResync: TRPCMutationProcedure<{
2423
2467
  input: {
2424
2468
  [x: string]: unknown;
@@ -29,6 +29,7 @@ export { cameraStreamsCapability } from '../capabilities/camera-streams.cap.js';
29
29
  export { carbonMonoxideCapability } from '../capabilities/carbon-monoxide.cap.js';
30
30
  export { climateControlCapability } from '../capabilities/climate-control.cap.js';
31
31
  export { colorCapability } from '../capabilities/color.cap.js';
32
+ export { connectionTestCapability } from '../capabilities/connection-test.cap.js';
32
33
  export { connectivityCapability } from '../capabilities/connectivity.cap.js';
33
34
  export { consumablesCapability } from '../capabilities/consumables.cap.js';
34
35
  export { contactCapability } from '../capabilities/contact.cap.js';
@@ -177,6 +178,7 @@ export declare const CAPABILITY_NAMES: {
177
178
  readonly carbonMonoxide: "carbon-monoxide";
178
179
  readonly climateControl: "climate-control";
179
180
  readonly color: "color";
181
+ readonly connectionTest: "connection-test";
180
182
  readonly connectivity: "connectivity";
181
183
  readonly consumables: "consumables";
182
184
  readonly contact: "contact";
@@ -338,6 +340,7 @@ export interface CapabilityRouterMap<TRouter = unknown> {
338
340
  readonly carbonMonoxide: TRouter;
339
341
  readonly climateControl: TRouter;
340
342
  readonly color: TRouter;
343
+ readonly connectionTest: TRouter;
341
344
  readonly connectivity: TRouter;
342
345
  readonly consumables: TRouter;
343
346
  readonly contact: TRouter;
@@ -459,8 +462,8 @@ export interface CapabilityRouterMap<TRouter = unknown> {
459
462
  export declare const SINGLETON_CAPABILITY_NAMES: readonly ["accessories", "addon-pages", "addon-settings", "addon-widgets", "addons", "admin-ui", "air-quality-sensor", "alarm-panel", "alerts", "ambient-light-sensor", "audio-analysis", "audio-analyzer", "audio-codec", "audio-metrics", "automation-control", "backup", "battery", "binary", "brightness", "button", "camera-credentials", "camera-pipeline-config", "camera-streams", "carbon-monoxide", "climate-control", "color", "connectivity", "consumables", "contact", "control", "core-blocks", "cover", "day-night", "decoder", "detection-pipeline", "device-adoption", "device-discovery", "device-manager", "device-ops", "device-state", "device-status", "doorbell", "enum-sensor", "event-emitter", "events", "face-gallery", "fan-control", "feature-probe", "filesystem-browse", "flood", "gas", "humidifier", "humidity-sensor", "image", "image-settings", "integrations", "intercom", "lawn-mower-control", "llm-runtime", "local-network", "lock-control", "media-player", "metrics-provider", "model-convert", "model-distributor", "motion", "motion-detection", "motion-trigger", "motion-zones", "native-object-detection", "network-quality", "nodes", "notification-rules", "notifier", "numeric-sensor", "osd", "osd-manager", "pet-feeder", "pipeline-analytics", "pipeline-executor", "pipeline-orchestrator", "pipeline-runner", "plate-gallery", "platform-probe", "power-meter", "presence", "pressure-sensor", "privacy-mask", "ptz", "ptz-autotrack", "reboot", "recording", "recordingExport", "scene-monitor", "script-runner", "server-management", "settings-store", "smoke", "snapshot", "sso-bridge", "storage", "stream-broker", "stream-catalog", "stream-params", "switch", "system", "tamper", "temperature-sensor", "terminal-session", "toast", "update", "user-management", "vacuum-control", "valve", "vector-store", "vibration", "videoclips", "viewer-ui", "water-heater", "weather", "webrtc-session", "zone-analytics", "zone-rules", "zones"];
460
463
  /** Union of singleton capability names (literal string union). */
461
464
  export type SingletonCapabilityName = typeof SINGLETON_CAPABILITY_NAMES[number];
462
- /** Capability names whose mode is `collection` (23 caps). */
463
- export declare const COLLECTION_CAPABILITY_NAMES: readonly ["addon-pages-source", "addon-routes", "addon-widgets-source", "auth-provider", "broker", "custom-model-registry", "data-store-provider", "device-export", "device-provider", "embedding-encoder", "llm", "log-destination", "login-method", "mesh-network", "mqtt-broker", "network-access", "notification-output", "oauth-integration", "smtp-provider", "storage-evictable", "storage-provider", "turn-provider", "user-passkeys"];
465
+ /** Capability names whose mode is `collection` (24 caps). */
466
+ export declare const COLLECTION_CAPABILITY_NAMES: readonly ["addon-pages-source", "addon-routes", "addon-widgets-source", "auth-provider", "broker", "connection-test", "custom-model-registry", "data-store-provider", "device-export", "device-provider", "embedding-encoder", "llm", "log-destination", "login-method", "mesh-network", "mqtt-broker", "network-access", "notification-output", "oauth-integration", "smtp-provider", "storage-evictable", "storage-provider", "turn-provider", "user-passkeys"];
464
467
  /** Union of collection capability names (literal string union). */
465
468
  export type CollectionCapabilityName = typeof COLLECTION_CAPABILITY_NAMES[number];
466
469
  /** Capability mode lookup at runtime — mirrors the `.cap.ts` definitions. */
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 901 method paths across 121 capabilities.
9
+ * Coverage: 906 method paths across 122 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -9,6 +9,7 @@ import type { audioAnalyzerCapability } from '../capabilities/audio-analyzer.cap
9
9
  import type { audioCodecCapability } from '../capabilities/audio-codec.cap.js';
10
10
  import type { backupCapability } from '../capabilities/backup.cap.js';
11
11
  import type { brokerCapability } from '../capabilities/broker.cap.js';
12
+ import type { connectionTestCapability } from '../capabilities/connection-test.cap.js';
12
13
  import type { coreBlocksCapability } from '../capabilities/core-blocks.cap.js';
13
14
  import type { decoderCapability } from '../capabilities/decoder.cap.js';
14
15
  import type { deviceAdoptionCapability } from '../capabilities/device-adoption.cap.js';
@@ -61,11 +62,12 @@ export interface SystemProxy {
61
62
  readonly audioCodec: Pick<InferProvider<typeof audioCodecCapability>, 'listSupportedCodecs' | 'canHandle' | 'createDecodeSession' | 'createEncodeSession' | 'closeSession' | 'pushEncodedFrame' | 'pullPcm' | 'pushPcm' | 'pullEncoded' | 'flushEncode' | 'listActiveSessions'>;
62
63
  readonly backup: Pick<InferProvider<typeof backupCapability>, 'listDestinations' | 'trigger' | 'list' | 'listLocations' | 'getEntries' | 'restore' | 'delete' | 'listArchives' | 'upsertDestinationPolicy' | 'previewSchedule' | 'listSchedules' | 'upsertSchedule' | 'deleteSchedule'>;
63
64
  readonly broker: Pick<InferProvider<typeof brokerCapability>, 'list' | 'get' | 'listProviders' | 'add' | 'remove' | 'testConnection' | 'getSettings' | 'setSettings' | 'getBrokerConfig' | 'getSettingsSchema' | 'testSettings' | 'publish' | 'subscribe' | 'unsubscribe' | 'getState' | 'getStatus'>;
65
+ readonly connectionTest: Pick<InferProvider<typeof connectionTestCapability>, 'testSettings' | 'describeTest'>;
64
66
  readonly coreBlocks: Pick<InferProvider<typeof coreBlocksCapability>, 'list' | 'get' | 'create' | 'update' | 'delete' | 'setEnabled' | 'restart' | 'compile' | 'getTypeDefs'>;
65
67
  readonly decoder: Pick<InferProvider<typeof decoderCapability>, 'supportsCodec' | 'getInfo' | 'createSession' | 'destroySession' | 'pushPacket' | 'openStream' | 'pullFrames' | 'pullHandles' | 'getFrame' | 'getShmStats' | 'updateConfig' | 'getStats' | 'listActiveSessions' | 'reprobeHwaccel'>;
66
68
  readonly deviceAdoption: Pick<InferProvider<typeof deviceAdoptionCapability>, 'listCandidateFilters' | 'listCandidates' | 'getCandidate' | 'refresh' | 'adopt' | 'release' | 'resync'>;
67
69
  readonly deviceExport: Pick<InferProvider<typeof deviceExportCapability>, 'getStatus' | 'listSupportedDeviceKinds' | 'listExposedDevices' | 'exposeDevice' | 'unexposeDevice'>;
68
- readonly deviceManager: Pick<InferProvider<typeof deviceManagerCapability>, 'allocateDeviceId' | 'registerDevice' | 'removeDevice' | 'persistConfig' | 'getRoleDisplayDefaults' | 'setRoleDisplayDefaults' | 'listLocations' | 'addLocation' | 'removeLocation' | 'listPersistedByAddon' | 'listAll' | 'getChildren' | 'removeByIntegration' | 'listWrappersForCap' | 'listBindableCapsForDeviceType' | 'discoverDevices' | 'adoptDevice' | 'getCreationSchema' | 'createDevice' | 'testCreationField' | 'adoptionListCandidateFilters' | 'adoptionListCandidates' | 'adoptionRefresh' | 'adoptionAdopt' | 'adoptionRelease' | 'adoptionResync' | 'discoveryProviders' | 'discoverAllProviders' | 'discoverProvider' | 'providerCreationType' | 'providerDiscoveryParamsSchema' | 'getDeviceStatusAggregateBatch'>;
70
+ readonly deviceManager: Pick<InferProvider<typeof deviceManagerCapability>, 'allocateDeviceId' | 'registerDevice' | 'removeDevice' | 'persistConfig' | 'getRoleDisplayDefaults' | 'setRoleDisplayDefaults' | 'listLocations' | 'addLocation' | 'removeLocation' | 'listPersistedByAddon' | 'listAll' | 'getChildren' | 'removeByIntegration' | 'listWrappersForCap' | 'listBindableCapsForDeviceType' | 'discoverDevices' | 'adoptDevice' | 'getCreationSchema' | 'createDevice' | 'testCreationField' | 'adoptionListCandidateFilters' | 'adoptionListCandidates' | 'adoptionRefresh' | 'adoptionAdopt' | 'adoptionRelease' | 'adoptionStartJob' | 'adoptionListJobs' | 'adoptionCancelJob' | 'adoptionResync' | 'discoveryProviders' | 'discoverAllProviders' | 'discoverProvider' | 'providerCreationType' | 'providerDiscoveryParamsSchema' | 'getDeviceStatusAggregateBatch'>;
69
71
  readonly deviceProvider: Pick<InferProvider<typeof deviceProviderCapability>, 'start' | 'stop' | 'getStatus' | 'getDevices' | 'supportsDiscovery' | 'discoverDevices' | 'getDiscoveryParamsSchema' | 'getManualCreationType' | 'adoptDiscoveredDevice' | 'supportsManualCreation' | 'getChildCreationSchema' | 'createDevice' | 'testCreationField'>;
70
72
  readonly deviceState: Pick<InferProvider<typeof deviceStateCapability>, 'getAllSnapshots'>;
71
73
  readonly faceGallery: Pick<InferProvider<typeof faceGalleryCapability>, 'listIdentities' | 'createIdentity' | 'renameIdentity' | 'deleteIdentity' | 'listIdentitySamples' | 'removeSample' | 'listRecentFaces' | 'getFaceMedia' | 'assignFace' | 'unassignFace' | 'deleteFace' | 'assignFaces' | 'unassignFaces' | 'suggestFaceClusters'>;
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export { DEFAULT_ADDON_PLACEMENT, isAgentOnlyPlacement, isDeployableToAgent, res
19
19
  export type * from './interfaces/addon-data-plane.js';
20
20
  export { DATAPLANE_SECRET_HEADER } from './interfaces/addon-data-plane.js';
21
21
  export type * from './interfaces/addon-routes.js';
22
+ export * from './interfaces/adoption-job.js';
22
23
  export type * from './interfaces/agent.js';
23
24
  export type * from './interfaces/agent-protocol.js';
24
25
  export * from './interfaces/agent-protocol.js';