@camstack/types 1.2.427 → 1.2.429

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.2.429] - 2026-10-27
11
+
12
+ ### Added
13
+
14
+ - pet-feeder reports bowlFood, eating and supportsMarkRefilled
15
+
16
+ ## [1.2.428] - 2026-10-27
17
+
18
+ ### Added
19
+
20
+ - The published package now includes its README and CHANGELOG.
21
+ - Cloud integrations raise one alert when their session is lost and clear it when it is back
22
+
23
+ ## [1.2.427] - 2026-10-27
24
+
25
+ ### Added
26
+
27
+ - CamStack Types: Shared types, interfaces, and model catalogs for the CamStack detection ecosystem.
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # CamStack Types
2
+
3
+ Shared types, interfaces, and model catalogs for the CamStack detection ecosystem.
4
+
5
+ <!-- readme:generated:start (derived from the manifest; edit outside this block) -->
6
+
7
+ Package `@camstack/types` on npm.
8
+
9
+ ## Documentation
10
+
11
+ - [docs/architecture/notifications.md](https://github.com/camstack/server/blob/main/docs/architecture/notifications.md)
12
+ - [docs/architecture/capabilities.md](https://github.com/camstack/server/blob/main/docs/architecture/capabilities.md)
13
+ - [docs/architecture/detection-execution.md](https://github.com/camstack/server/blob/main/docs/architecture/detection-execution.md)
14
+ - [docs/architecture/ffmpeg.md](https://github.com/camstack/server/blob/main/docs/architecture/ffmpeg.md)
15
+ - [packages/types/AGENTS.md](https://github.com/camstack/server/blob/main/packages/types/AGENTS.md)
16
+
17
+ See [CHANGELOG.md](./CHANGELOG.md) for what changed in each version.
18
+
19
+ <!-- readme:generated:end -->
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Session health — the STANDARD "cloud connection lost" alert (D-session-health).
3
+ *
4
+ * Every addon that keeps a cloud session for an integration (an account login, a
5
+ * refresh token, a long-lived socket) reports two facts and nothing else:
6
+ *
7
+ * - `lost(integrationId, …)` the session was refused / kicked / dropped;
8
+ * - `restored(integrationId)` a call went through again.
9
+ *
10
+ * The tracker owns everything between: a debounce (a transient reconnect never
11
+ * alerts), ONE alert per integration instance (never one per device, never one
12
+ * per failed poll), the wording (provider, integration, reason), an action the
13
+ * operator can follow, and the automatic resolve when the session is back.
14
+ *
15
+ * Alerts are durable state that the next run of the addon cannot see, so the
16
+ * first `restored()` of a process resolves whatever a previous run left active.
17
+ */
18
+ import type { Alert, AlertSeverity } from '../capabilities/alerts.cap.js';
19
+ import type { IScopedLogger } from '../interfaces/logging.js';
20
+ /** Why the session ended. `kicked` = the same account signed in elsewhere. */
21
+ export type SessionLossReason = 'kicked' | 'auth-rejected' | 'token-expired' | 'connection-lost';
22
+ /** What an alert's action looks like (the `Alert.action` shape). */
23
+ export interface SessionAlertAction {
24
+ readonly label: string;
25
+ readonly href?: string;
26
+ readonly navigation?: 'app' | 'server';
27
+ }
28
+ /** The slice of `ctx.api.alerts` the tracker needs. Structural, so `ctx.api.alerts` fits. */
29
+ export interface SessionHealthAlertsPort {
30
+ readonly emit?: {
31
+ mutate(alert: Alert): Promise<unknown>;
32
+ };
33
+ readonly update?: {
34
+ mutate(input: {
35
+ readonly alertId: string;
36
+ readonly patch: Partial<Alert>;
37
+ }): Promise<unknown>;
38
+ };
39
+ }
40
+ export declare const SESSION_LOST_ALERT_CATEGORY = "integration.session-lost";
41
+ /** A transient reconnect is quiet for this long before it is worth an alert. */
42
+ export declare const DEFAULT_SESSION_LOST_DEBOUNCE_MS: number;
43
+ export declare function sessionLostAlertId(kind: string, integrationId: string): string;
44
+ export interface BuildSessionLostAlertInput {
45
+ /** Stable provider key, e.g. `petkit` — part of the alert id and source. */
46
+ readonly kind: string;
47
+ /** Display name, e.g. `PetKit`. */
48
+ readonly providerName: string;
49
+ readonly integrationId: string;
50
+ readonly integrationName: string;
51
+ readonly reason: SessionLossReason;
52
+ /** Defaults to "Open integration" (the admin integration page). */
53
+ readonly action?: SessionAlertAction;
54
+ readonly severity?: AlertSeverity;
55
+ readonly now?: number;
56
+ }
57
+ /** Pure builder, exported so an addon with its own flow can still emit the standard shape. */
58
+ export declare function buildSessionLostAlert(input: BuildSessionLostAlertInput): Alert;
59
+ export interface SessionHealthTrackerOptions {
60
+ readonly kind: string;
61
+ readonly providerName: string;
62
+ readonly logger: IScopedLogger;
63
+ /** Read lazily: `ctx.api.alerts` may be absent early in boot. */
64
+ readonly getAlerts: () => SessionHealthAlertsPort | undefined;
65
+ readonly debounceMs?: number;
66
+ }
67
+ export interface SessionLostInfo {
68
+ readonly integrationName: string;
69
+ readonly reason: SessionLossReason;
70
+ /** Re-auth route when the addon has one; otherwise "Open integration". */
71
+ readonly action?: SessionAlertAction;
72
+ }
73
+ export declare class SessionHealthTracker {
74
+ #private;
75
+ constructor(opts: SessionHealthTrackerOptions);
76
+ /** The session is gone. Idempotent: call it on every failed poll. */
77
+ lost(integrationId: string, info: SessionLostInfo): void;
78
+ /** A call went through. Idempotent: call it on every successful poll. */
79
+ restored(integrationId: string): Promise<void>;
80
+ /** The integration is gone (deleted / disabled): drop its state and its alert. */
81
+ forget(integrationId: string): Promise<void>;
82
+ /** Stop every pending timer (addon shutdown). */
83
+ dispose(): void;
84
+ }
85
+ export interface IntegrationSessionBinding {
86
+ readonly logger: IScopedLogger;
87
+ readonly getAlerts: () => SessionHealthAlertsPort | undefined;
88
+ readonly debounceMs?: number;
89
+ }
90
+ export interface IntegrationSessionReporterOptions {
91
+ readonly kind: string;
92
+ readonly providerName: string;
93
+ /**
94
+ * Is `err` the cloud ending OUR session (kicked, token refused, sign-in
95
+ * rejected)? `null` for anything else — a network blip or a per-device error
96
+ * must never read as a lost session.
97
+ */
98
+ readonly classify: (err: unknown) => SessionLossReason | null;
99
+ /** Re-auth route when the addon has one; otherwise "Open integration". */
100
+ readonly action?: (integrationId: string) => SessionAlertAction | undefined;
101
+ }
102
+ /**
103
+ * The addon-facing face of {@link SessionHealthTracker}: a process-wide object an
104
+ * integration manager AND its device classes can reach (the kernel builds a
105
+ * device from a `DeviceContext` alone, so neither can be handed a tracker).
106
+ * The addon `bind()`s it in `onInitialize`, `unbind()`s it on shutdown and
107
+ * `forget()`s an integration that vanished; everything before `bind` is a no-op.
108
+ */
109
+ export declare class IntegrationSessionReporter {
110
+ #private;
111
+ constructor(opts: IntegrationSessionReporterOptions);
112
+ bind(binding: IntegrationSessionBinding): void;
113
+ unbind(): void;
114
+ /** The manager tells us the display name once, so a device can report by id alone. */
115
+ register(integrationId: string, integrationName: string): void;
116
+ /** A call failed. Only a session-ending failure counts; anything else is ignored. */
117
+ failure(integrationId: string, err: unknown): void;
118
+ /** A call went through. */
119
+ ok(integrationId: string): Promise<void>;
120
+ /** The integration was removed. */
121
+ forget(integrationId: string): Promise<void>;
122
+ }
123
+ /** What a manager / device depends on to report. */
124
+ export type IntegrationSessionSink = Pick<IntegrationSessionReporter, 'register' | 'failure' | 'ok'>;
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-edKiOXLo.js");
2
+ const require_sleep = require("./sleep-hRhTSDlN.js");
3
3
  const require_event_category = require("./event-category-Ave2VSxY.js");
4
4
  const require_err_msg = require("./err-msg-U7lLUMNz.js");
5
5
  //#region src/generated/cap-input-defaults.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as expandCapMethods, $n as REVALIDATE_AFTER_MS, $r as isSecretMarker, $t as RecordFieldPathSchema, A as HF_REPO, An as RecordUniqueViolationError, Ar as buildSecretRef, B as withoutCallerStamp, Bn as RECORD_CLASSES, C as addonSliceHandleApi, Cn as InvalidRecordError, Dn as RecordNotFoundError, En as RECORDS_ERROR_CODES, Fn as UnknownRecordKindError, Fr as parseSecretRef, G as adminUiCapability, Gn as RECORD_MAX_DATA_BYTES, Hn as RECORD_DEFAULT_MAX_DATA_BYTES, I as deviceOpsCapability, In as asRecordsError, Jn as RECORD_QUERY_MAX, Jt as defineEntryKind, Kn as RECORD_MAX_INDEXES, L as viewerUiCapability, Ln as recordsErrorFromMessage, M as CAP_ADVANCE_FIELDS, Mn as RevConflictError, Mr as globalSecretScope, Nn as TransactRefusedError, Nr as isSecretRef, On as RecordSecretUnavailableError, Or as SECRET_REF_SCHEME, P as CAP_STATE_LEAVES, Pn as UnindexedFilterError, Pr as normalizeSecretOwner, Qn as resolveSecretViewsIn, Qr as isSecretFieldView, Qt as EntryDescriptorSchema, R as DEVICE_CHILDREN_BATCH_MAX, Rn as RECORD_BATCH_MAX, Rr as createEvent, Sn as ForeignSecretMarkerError, Tn as PlaintextSecretError, U as describeCustomActions, Un as RECORD_DELETE_BATCH, Vn as RECORD_DATABASES, Wn as RECORD_ID_MAX_LENGTH, Xn as RECORD_SETTINGS_MAX_ROWS, Xr as classifySecretWrite, Xt as createRecordsAccess, Yn as RECORD_SECRET_COLLECTION_PREFIX, Yr as SECRET_CLEAR, Yt as entryBody, Zn as RECORD_SWEEP_INTERVAL_MS, Zr as isSecretClear, Zt as assertTransactScope, _ as readErrorI18n, _n as collectZodSecretPaths, an as assertValidDeclaration, ar as registerKnownSecret, b as isDeviceScopedCap, bn as DeclarationRefusedError, c as asString, cn as REMOVE_LEAF, cr as PEER_BYTES_CHUNK_BYTES, ct as readNodePin, d as parseJsonUnknown, dn as parseSecretPath, dr as PEER_BYTES_TICKET_TTL_MS, dt as ReadinessRegistry, ei as isSecretMarkerLike, en as RecordIndexSchema, er as createSecretsAccess, f as hfModelUrl, fn as recordArrayItemPath, ft as ReadinessTimeoutError, g as ErrorI18nPayloadSchema, gr as BaseAddon, hn as secretArrayPrefixes, hr as DisposerChain, ht as scopeKey, in as StoredRecordKindDeclarationSchema, ir as knownSecretCount, jn as RecordsError, jr as formatSecretScope, kn as RecordTooLargeError, kr as arrayItemFieldPath, ln as collectSecretLeaves, lr as PEER_BYTES_MAX_OUTSTANDING, mn as recordSecretRef, ni as toSecretFieldView, nn as RecordKindNameSchema, nr as clearKnownSecrets, o as asJsonObject, on as declarationsOf, or as scrubKnownSecrets, p as BOOT_RECOVERY_BACKOFF_MS, pn as recordSecretCollection, pr as DATAPLANE_SECRET_HEADER, qn as RECORD_MAX_INDEX_FIELDS, qt as makeInMemoryRecords, r as maskUrlCredentials, rn as RecordRetentionSchema, rr as forgetKnownSecret, sn as defineRecordKinds, sr as shortSecretRefHash, st as nodePin, t as sleep, ti as makeSecretMarker, tn as RecordKindDeclarationSchema, tr as MIN_SCRUBBED_LENGTH, un as mapSecretLeaves, ur as PEER_BYTES_STALL_MS, ut as MODEL_FORMATS, vn as isZodSecret, vr as normalizeAddonInitResult, w as createEventBusSliceSource, wn as NoCallerError, x as createDeviceProxy, xn as FilterRequiredError, y as DEVICE_SCOPED_CAPS, yn as BatchTooLargeError, z as CALLER_STAMPED_CAPABILITIES, zn as RECORD_BATCH_MAX_BYTES, zr as emitReadiness } from "./sleep--jXS9hWo.mjs";
1
+ import { $ as expandCapMethods, $n as REVALIDATE_AFTER_MS, $r as isSecretMarker, $t as RecordFieldPathSchema, A as HF_REPO, An as RecordUniqueViolationError, Ar as buildSecretRef, B as withoutCallerStamp, Bn as RECORD_CLASSES, C as addonSliceHandleApi, Cn as InvalidRecordError, Dn as RecordNotFoundError, En as RECORDS_ERROR_CODES, Fn as UnknownRecordKindError, Fr as parseSecretRef, G as adminUiCapability, Gn as RECORD_MAX_DATA_BYTES, Hn as RECORD_DEFAULT_MAX_DATA_BYTES, I as deviceOpsCapability, In as asRecordsError, Jn as RECORD_QUERY_MAX, Jt as defineEntryKind, Kn as RECORD_MAX_INDEXES, L as viewerUiCapability, Ln as recordsErrorFromMessage, M as CAP_ADVANCE_FIELDS, Mn as RevConflictError, Mr as globalSecretScope, Nn as TransactRefusedError, Nr as isSecretRef, On as RecordSecretUnavailableError, Or as SECRET_REF_SCHEME, P as CAP_STATE_LEAVES, Pn as UnindexedFilterError, Pr as normalizeSecretOwner, Qn as resolveSecretViewsIn, Qr as isSecretFieldView, Qt as EntryDescriptorSchema, R as DEVICE_CHILDREN_BATCH_MAX, Rn as RECORD_BATCH_MAX, Rr as createEvent, Sn as ForeignSecretMarkerError, Tn as PlaintextSecretError, U as describeCustomActions, Un as RECORD_DELETE_BATCH, Vn as RECORD_DATABASES, Wn as RECORD_ID_MAX_LENGTH, Xn as RECORD_SETTINGS_MAX_ROWS, Xr as classifySecretWrite, Xt as createRecordsAccess, Yn as RECORD_SECRET_COLLECTION_PREFIX, Yr as SECRET_CLEAR, Yt as entryBody, Zn as RECORD_SWEEP_INTERVAL_MS, Zr as isSecretClear, Zt as assertTransactScope, _ as readErrorI18n, _n as collectZodSecretPaths, an as assertValidDeclaration, ar as registerKnownSecret, b as isDeviceScopedCap, bn as DeclarationRefusedError, c as asString, cn as REMOVE_LEAF, cr as PEER_BYTES_CHUNK_BYTES, ct as readNodePin, d as parseJsonUnknown, dn as parseSecretPath, dr as PEER_BYTES_TICKET_TTL_MS, dt as ReadinessRegistry, ei as isSecretMarkerLike, en as RecordIndexSchema, er as createSecretsAccess, f as hfModelUrl, fn as recordArrayItemPath, ft as ReadinessTimeoutError, g as ErrorI18nPayloadSchema, gr as BaseAddon, hn as secretArrayPrefixes, hr as DisposerChain, ht as scopeKey, in as StoredRecordKindDeclarationSchema, ir as knownSecretCount, jn as RecordsError, jr as formatSecretScope, kn as RecordTooLargeError, kr as arrayItemFieldPath, ln as collectSecretLeaves, lr as PEER_BYTES_MAX_OUTSTANDING, mn as recordSecretRef, ni as toSecretFieldView, nn as RecordKindNameSchema, nr as clearKnownSecrets, o as asJsonObject, on as declarationsOf, or as scrubKnownSecrets, p as BOOT_RECOVERY_BACKOFF_MS, pn as recordSecretCollection, pr as DATAPLANE_SECRET_HEADER, qn as RECORD_MAX_INDEX_FIELDS, qt as makeInMemoryRecords, r as maskUrlCredentials, rn as RecordRetentionSchema, rr as forgetKnownSecret, sn as defineRecordKinds, sr as shortSecretRefHash, st as nodePin, t as sleep, ti as makeSecretMarker, tn as RecordKindDeclarationSchema, tr as MIN_SCRUBBED_LENGTH, un as mapSecretLeaves, ur as PEER_BYTES_STALL_MS, ut as MODEL_FORMATS, vn as isZodSecret, vr as normalizeAddonInitResult, w as createEventBusSliceSource, wn as NoCallerError, x as createDeviceProxy, xn as FilterRequiredError, y as DEVICE_SCOPED_CAPS, yn as BatchTooLargeError, z as CALLER_STAMPED_CAPABILITIES, zn as RECORD_BATCH_MAX_BYTES, zr as emitReadiness } from "./sleep-BE7IAR2p.mjs";
2
2
  import { t as EventCategory } from "./event-category-CT-hz5Rb.mjs";
3
3
  import { a as DeviceType, t as errMsg } from "./err-msg-DIorGYeC.mjs";
4
4
  //#region src/generated/cap-input-defaults.ts
@@ -38,7 +38,7 @@ export type NetworkEndpoint = z.infer<typeof NetworkEndpointSchema>;
38
38
  export type NetworkTunnelStartedData = z.infer<typeof NetworkTunnelStartedDataSchema>;
39
39
  /**
40
40
  * Optional, richer endpoint shape returned by providers that expose
41
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
41
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
42
42
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43
43
  * the originating provider config (mode + sourcePort) so the
44
44
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46,6 +46,9 @@ export declare const PetFeederDeviceStatusSchema: z.ZodEnum<{
46
46
  export type PetFeederDeviceStatus = z.infer<typeof PetFeederDeviceStatusSchema>;
47
47
  export declare const PetFeederStatusSchema: z.ZodObject<{
48
48
  foodLevel: z.ZodNullable<z.ZodNumber>;
49
+ bowlFood: z.ZodNullable<z.ZodNumber>;
50
+ eating: z.ZodBoolean;
51
+ supportsMarkRefilled: z.ZodBoolean;
49
52
  food1: z.ZodNullable<z.ZodNumber>;
50
53
  food2: z.ZodNullable<z.ZodNumber>;
51
54
  lowFood: z.ZodBoolean;
@@ -95,7 +98,9 @@ export declare const petFeederCapability: {
95
98
  readonly resetDesiccant: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
96
99
  deviceId: z.ZodNumber;
97
100
  }, z.core.$strip>, z.ZodVoid, "mutation">;
98
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
101
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
102
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
103
+ * change any sensor reading. */
99
104
  readonly markFoodReplenished: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
100
105
  deviceId: z.ZodNumber;
101
106
  }, z.core.$strip>, z.ZodVoid, "mutation">;
@@ -132,6 +137,9 @@ export declare const petFeederCapability: {
132
137
  readonly status: {
133
138
  readonly schema: z.ZodObject<{
134
139
  foodLevel: z.ZodNullable<z.ZodNumber>;
140
+ bowlFood: z.ZodNullable<z.ZodNumber>;
141
+ eating: z.ZodBoolean;
142
+ supportsMarkRefilled: z.ZodBoolean;
135
143
  food1: z.ZodNullable<z.ZodNumber>;
136
144
  food2: z.ZodNullable<z.ZodNumber>;
137
145
  lowFood: z.ZodBoolean;
@@ -161,6 +169,9 @@ export declare const petFeederCapability: {
161
169
  */
162
170
  readonly runtimeState: z.ZodObject<{
163
171
  foodLevel: z.ZodNullable<z.ZodNumber>;
172
+ bowlFood: z.ZodNullable<z.ZodNumber>;
173
+ eating: z.ZodBoolean;
174
+ supportsMarkRefilled: z.ZodBoolean;
164
175
  food1: z.ZodNullable<z.ZodNumber>;
165
176
  food2: z.ZodNullable<z.ZodNumber>;
166
177
  lowFood: z.ZodBoolean;
@@ -196,6 +207,9 @@ export declare const petFeederCapability: {
196
207
  readonly foodLevel: {
197
208
  readonly kind: 'gauge';
198
209
  };
210
+ readonly bowlFood: {
211
+ readonly kind: 'gauge';
212
+ };
199
213
  readonly food1: {
200
214
  readonly kind: 'gauge';
201
215
  };
@@ -5,7 +5,7 @@
5
5
  * `ALL_CAPABILITY_DEFINITIONS` (the whole Zod schema graph, ~+100 MB heap per
6
6
  * runner). See docs/decisions/adr-0028.md.
7
7
  *
8
- * Coverage: 1 advance-derived caps, 77 caps with 353 state leaves.
8
+ * Coverage: 1 advance-derived caps, 77 caps with 356 state leaves.
9
9
  */
10
10
  /** A bindable scalar in a capability's runtime state. */
11
11
  export interface CapStateLeaf {
@@ -1,7 +1,7 @@
1
1
  import type { CapabilityHistoryField, CapabilityHistoryItems } from '../capabilities/capability-definition.js';
2
2
  /**
3
3
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
4
- * 42 caps with series (76 series), 33 caps answered `'none'`.
4
+ * 42 caps with series (77 series), 33 caps answered `'none'`.
5
5
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
6
6
  */
7
7
  export declare const HISTORY_CATALOG: Readonly<Record<string, Readonly<Record<string, CapabilityHistoryField>>>>;
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ export { BaseAddon, classifyStoreError, normalizeAddonInitResult } from './addon
6
6
  export { normalizeNodeId } from './addon/per-node-store.js';
7
7
  export type { AddonRouteInvokeRequest, AddonRouteReplyEnvelope, } from './addon/build-addon-route-provider.js';
8
8
  export { buildAddonRouteProvider } from './addon/build-addon-route-provider.js';
9
+ export type { BuildSessionLostAlertInput, IntegrationSessionBinding, IntegrationSessionReporterOptions, IntegrationSessionSink, SessionAlertAction, SessionHealthAlertsPort, SessionHealthTrackerOptions, SessionLossReason, SessionLostInfo, } from './addon/session-health.js';
10
+ export { buildSessionLostAlert, DEFAULT_SESSION_LOST_DEBOUNCE_MS, IntegrationSessionReporter, SESSION_LOST_ALERT_CATEGORY, SessionHealthTracker, sessionLostAlertId, } from './addon/session-health.js';
9
11
  export type { DurableState, DurableStateDeps } from './addon/durable-state.js';
10
12
  export { createDurableState } from './addon/durable-state.js';
11
13
  export type { IAuthProvider } from './capabilities/auth-provider.cap.js';