@krischoichoi/channel-control 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +67 -0
  2. package/lib/access/conversation-directory-store.d.ts +73 -0
  3. package/lib/access/conversation-directory-store.d.ts.map +1 -0
  4. package/lib/access/conversation-directory-store.js +66 -0
  5. package/lib/access/conversation-directory-store.js.map +1 -0
  6. package/lib/access/conversation-directory.d.ts +51 -0
  7. package/lib/access/conversation-directory.d.ts.map +1 -0
  8. package/lib/access/conversation-directory.js +118 -0
  9. package/lib/access/conversation-directory.js.map +1 -0
  10. package/lib/access/manager.d.ts +47 -0
  11. package/lib/access/manager.d.ts.map +1 -0
  12. package/lib/access/manager.js +124 -0
  13. package/lib/access/manager.js.map +1 -0
  14. package/lib/access/materialize.d.ts +33 -0
  15. package/lib/access/materialize.d.ts.map +1 -0
  16. package/lib/access/materialize.js +67 -0
  17. package/lib/access/materialize.js.map +1 -0
  18. package/lib/access/owner-claim.d.ts +91 -0
  19. package/lib/access/owner-claim.d.ts.map +1 -0
  20. package/lib/access/owner-claim.js +200 -0
  21. package/lib/access/owner-claim.js.map +1 -0
  22. package/lib/access/policy-store.d.ts +55 -0
  23. package/lib/access/policy-store.d.ts.map +1 -0
  24. package/lib/access/policy-store.js +88 -0
  25. package/lib/access/policy-store.js.map +1 -0
  26. package/lib/access/validation.d.ts +29 -0
  27. package/lib/access/validation.d.ts.map +1 -0
  28. package/lib/access/validation.js +89 -0
  29. package/lib/access/validation.js.map +1 -0
  30. package/lib/auth/sanitizer.d.ts +35 -0
  31. package/lib/auth/sanitizer.d.ts.map +1 -0
  32. package/lib/auth/sanitizer.js +52 -0
  33. package/lib/auth/sanitizer.js.map +1 -0
  34. package/lib/auth/session-manager.d.ts +38 -0
  35. package/lib/auth/session-manager.d.ts.map +1 -0
  36. package/lib/auth/session-manager.js +219 -0
  37. package/lib/auth/session-manager.js.map +1 -0
  38. package/lib/config.d.ts +20 -0
  39. package/lib/config.d.ts.map +1 -0
  40. package/lib/config.js +15 -0
  41. package/lib/config.js.map +1 -0
  42. package/lib/credentials/manager.d.ts +44 -0
  43. package/lib/credentials/manager.d.ts.map +1 -0
  44. package/lib/credentials/manager.js +24 -0
  45. package/lib/credentials/manager.js.map +1 -0
  46. package/lib/definitions/registry.d.ts +24 -0
  47. package/lib/definitions/registry.d.ts.map +1 -0
  48. package/lib/definitions/registry.js +59 -0
  49. package/lib/definitions/registry.js.map +1 -0
  50. package/lib/errors.d.ts +20 -0
  51. package/lib/errors.d.ts.map +1 -0
  52. package/lib/errors.js +45 -0
  53. package/lib/errors.js.map +1 -0
  54. package/lib/index.d.ts +31 -0
  55. package/lib/index.d.ts.map +1 -0
  56. package/lib/index.js +31 -0
  57. package/lib/index.js.map +1 -0
  58. package/lib/plugin.d.ts +20 -0
  59. package/lib/plugin.d.ts.map +1 -0
  60. package/lib/plugin.js +81 -0
  61. package/lib/plugin.js.map +1 -0
  62. package/lib/runtime/manager.d.ts +73 -0
  63. package/lib/runtime/manager.d.ts.map +1 -0
  64. package/lib/runtime/manager.js +277 -0
  65. package/lib/runtime/manager.js.map +1 -0
  66. package/lib/runtime/mount-handle.d.ts +11 -0
  67. package/lib/runtime/mount-handle.d.ts.map +1 -0
  68. package/lib/runtime/mount-handle.js +2 -0
  69. package/lib/runtime/mount-handle.js.map +1 -0
  70. package/lib/service.d.ts +180 -0
  71. package/lib/service.d.ts.map +1 -0
  72. package/lib/service.js +432 -0
  73. package/lib/service.js.map +1 -0
  74. package/lib/types.d.ts +370 -0
  75. package/lib/types.d.ts.map +1 -0
  76. package/lib/types.js +2 -0
  77. package/lib/types.js.map +1 -0
  78. package/lib/update-check.d.ts +128 -0
  79. package/lib/update-check.d.ts.map +1 -0
  80. package/lib/update-check.js +380 -0
  81. package/lib/update-check.js.map +1 -0
  82. package/package.json +47 -0
package/lib/types.d.ts ADDED
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Public type surface of @krischoichoi/channel-control.
3
+ *
4
+ * These types define the stable boundary between the Channel Control Plane
5
+ * and every downstream consumer (channel adapters, the Web control plane in
6
+ * channel-web, and future provider auth helpers). Platform differences stop
7
+ * here: channel-control itself is adapter-agnostic and never branches on a
8
+ * specific channel id.
9
+ *
10
+ * Host-only types ([InternalAuthSession], [AuthProviderSession]) must never
11
+ * cross the browser boundary — see auth/sanitizer.ts for the public DTOs.
12
+ */
13
+ import type { ChannelAccessPolicy, ChannelAdapter, ChannelHealth } from '@krischoichoi/channel-core';
14
+ /** How a channel begins an authorization flow (doc §15). */
15
+ export type AuthMethod = 'qr' | 'device' | 'portal-login' | 'credentials' | 'hybrid';
16
+ /**
17
+ * Fine-grained progress of an auth flow (doc §15/§16). The UI switches on
18
+ * this value rather than parsing free-form [PublicAuthStatus.detail] text.
19
+ */
20
+ export type AuthPhase = 'preparing' | 'waiting-scan' | 'scanned' | 'waiting-confirm' | 'verification-required' | 'credentials-required' | 'authorized' | 'expired' | 'failed' | 'cancelled';
21
+ /** Coarse public auth state, kept M1-compatible (doc §15). */
22
+ export type AuthState = 'pending' | 'authenticated' | 'expired' | 'failed';
23
+ /**
24
+ * Structured QR payload (doc §17). Replaces the ambiguous bare string:
25
+ * a value is either opaque content to render, a ready-made data URL, or an
26
+ * external URL to open.
27
+ */
28
+ export interface PublicQrPayload {
29
+ kind: 'content' | 'data-url' | 'external-url';
30
+ value: string;
31
+ expiresAt?: number;
32
+ }
33
+ /** Structured user-facing prompt associated with a phase (doc §16). */
34
+ export interface PublicAuthPrompt {
35
+ kind: 'verification-code' | 'confirm-on-phone' | 'credentials-required' | 'open-browser';
36
+ message?: string;
37
+ }
38
+ /** Public auth status returned by polling (doc §16). */
39
+ export interface PublicAuthStatus {
40
+ state: AuthState;
41
+ phase: AuthPhase;
42
+ prompt?: PublicAuthPrompt;
43
+ expiresAt?: number;
44
+ detail?: string;
45
+ }
46
+ /**
47
+ * Browser-facing session (doc §18). It NEVER contains secrets, tokens, the
48
+ * provider challenge or any provider payload. Build it exclusively through
49
+ * auth/sanitizer.ts.
50
+ */
51
+ export interface PublicAuthSession {
52
+ id: string;
53
+ channelId: string;
54
+ state: AuthState;
55
+ phase: AuthPhase;
56
+ qr?: PublicQrPayload;
57
+ expiresAt?: number;
58
+ prompt?: PublicAuthPrompt;
59
+ /**
60
+ * Safe provider polling interval (ms) the browser may use to space its own
61
+ * client polls (doc §15). NOT a secret: it is the provider's declared
62
+ * throttle and the host already enforces the same bound server-side via
63
+ * `nextPollAt`. Omitted unless the provider declared one (> 0).
64
+ */
65
+ pollingIntervalMs?: number;
66
+ }
67
+ /**
68
+ * Host-only full session (doc §18). Holds the AbortController and opaque
69
+ * provider state. Must never be serialized to the browser.
70
+ */
71
+ export interface InternalAuthSession {
72
+ id: string;
73
+ channelId: string;
74
+ accountId: string;
75
+ provider: string;
76
+ createdAt: number;
77
+ expiresAt: number;
78
+ pollingIntervalMs: number;
79
+ nextPollAt: number;
80
+ deviceCode?: string;
81
+ challenge?: unknown;
82
+ abortController: AbortController;
83
+ providerState: unknown;
84
+ }
85
+ /** Input that begins an auth flow (doc §14/§19). */
86
+ export interface AuthBeginInput {
87
+ method: AuthMethod;
88
+ accountId?: string;
89
+ }
90
+ /**
91
+ * What a definition's [ChannelDefinition.beginAuth] returns (doc §14/§19).
92
+ * Provider-specific and host-only. [providerState] is opaque and handed back
93
+ * verbatim to [ChannelDefinition.pollAuth] / [ChannelDefinition.submitAuthInput].
94
+ */
95
+ export interface AuthProviderSession {
96
+ provider: string;
97
+ expiresAt: number;
98
+ pollingIntervalMs: number;
99
+ qr?: PublicQrPayload;
100
+ prompt?: PublicAuthPrompt;
101
+ deviceCode?: string;
102
+ /** Opaque provider state; pollAuth/submitAuthInput receive this object back. */
103
+ providerState: unknown;
104
+ }
105
+ /** Auth input submitted during a flow (e.g. a verification code). */
106
+ export interface AuthInput {
107
+ kind: 'verification-code';
108
+ value: string;
109
+ }
110
+ /** One selectable setup field of a channel (doc §29). */
111
+ export interface ChannelSetupField {
112
+ name: string;
113
+ kind: 'text' | 'secret';
114
+ secret: boolean;
115
+ configured: boolean;
116
+ writable: boolean;
117
+ /**
118
+ * Credential reference name for secret fields (doc §31). The web layer
119
+ * never sees this — the control plane maps a field name to its ref and
120
+ * calls ctx.credentials. Non-secret fields omit it.
121
+ */
122
+ ref?: string;
123
+ /**
124
+ * Current value for NON-secret fields only (doc §29). Populated dynamically
125
+ * by ChannelControlService.getSetup from ConfiguredState; secret fields never
126
+ * carry it, and static definition.setup.fields leave it undefined.
127
+ */
128
+ value?: string;
129
+ }
130
+ /** Static setup descriptor advertising a channel's editable surface (doc §29). */
131
+ export interface ChannelSetupDescriptor {
132
+ fields: ChannelSetupField[];
133
+ authMethods: AuthMethod[];
134
+ /** Optional official console where users obtain the required credentials. */
135
+ setupUrl?: string;
136
+ }
137
+ /** One-shot setup payload used by the Web form. Secret values stay host-side. */
138
+ export interface ChannelSetupInput {
139
+ config: Record<string, unknown>;
140
+ credentials: Record<string, string>;
141
+ /**
142
+ * Whether a successful save immediately reconciles the channel runtime.
143
+ * Defaults to true. Interactive authorization can persist prerequisite
144
+ * credentials first, then start the provider auth flow without mounting an
145
+ * adapter that is not authorized yet.
146
+ */
147
+ reconcile?: boolean;
148
+ }
149
+ /** Result of saving setup and reconciling the channel runtime. */
150
+ export interface ChannelSetupResult {
151
+ configured: boolean;
152
+ connection: ChannelRuntimeStatus['connection'];
153
+ }
154
+ /**
155
+ * Dynamic configured state: never returns secret values (doc §14/§29).
156
+ * Per-field `value` carries non-secret config values only (e.g. appId/clientId);
157
+ * secret fields never set it.
158
+ */
159
+ export interface ConfiguredState {
160
+ configured: boolean;
161
+ fields: Record<string, {
162
+ configured: boolean;
163
+ writable: boolean;
164
+ source?: string;
165
+ value?: string;
166
+ }>;
167
+ }
168
+ /**
169
+ * Runtime status of one mounted (or not) channel (doc §60 / ChannelSummary).
170
+ */
171
+ export interface ChannelRuntimeStatus {
172
+ mounted: boolean;
173
+ running: boolean;
174
+ connection: 'connected' | 'degraded' | 'disconnected' | 'unknown';
175
+ health?: ChannelHealth | null;
176
+ lastError?: string | null;
177
+ }
178
+ /**
179
+ * How a channel determines its local operator / owner identity.
180
+ * - `account`: the domain account is identified up front (e.g. Weixin's
181
+ * scanning QR userId); owner is bootstrapped automatically.
182
+ * - `claim`: no upfront identity; the owner identifies themselves via the
183
+ * reserved `/dsh-claim` flow.
184
+ * - `manual`: the owner is assigned manually by the operator.
185
+ * - `platform`: the platform restricts private messages to the bot creator;
186
+ * no local owner claim is needed.
187
+ */
188
+ export type OwnerDiscoveryMode = 'account' | 'claim' | 'manual' | 'platform';
189
+ /**
190
+ * Declared access capability of a channel. Adapters publish it; the
191
+ * control plane and harness use it to decide what a policy may express and
192
+ * whether owner bootstrap applies.
193
+ */
194
+ export interface ChannelAccessDescriptor {
195
+ directMessages: boolean;
196
+ groups: boolean;
197
+ mentions: boolean;
198
+ ownerDiscovery: OwnerDiscoveryMode;
199
+ identityLabels: {
200
+ user: string;
201
+ group?: string;
202
+ };
203
+ defaults?: {
204
+ requireMention?: boolean;
205
+ };
206
+ /**
207
+ * Conversation identity presentation metadata (generic — the Web renders
208
+ * from this, never from per-channel conditionals). Declared by channels
209
+ * whose adapters expose a discovered conversation identity list (e.g. QQ
210
+ * group_openid).
211
+ */
212
+ identity?: {
213
+ conversation?: {
214
+ /** Label for an optional human-facing id when the platform provides one. */
215
+ externalIdLabel?: string;
216
+ /**
217
+ * True when the Web must select groups from the conversation directory
218
+ * rather than accept a typed identity.
219
+ */
220
+ conversationDiscoverable?: boolean;
221
+ };
222
+ };
223
+ }
224
+ /**
225
+ * High-level access state of a channel, surfaced to the Web control
226
+ * plane so an operator can see at a glance why inbound is gated.
227
+ */
228
+ export type ChannelAccessReadiness = 'ready' | 'needs-owner' | 'missing-policy' | 'invalid-policy';
229
+ /**
230
+ * Full access picture for one channel+account. The `policy` carries
231
+ * canonical sender/group IDs — never any secret — because these are exactly what
232
+ * the operator edits in the ACL.
233
+ */
234
+ export interface ChannelAccessState {
235
+ descriptor: ChannelAccessDescriptor;
236
+ readiness: ChannelAccessReadiness;
237
+ policy?: ChannelAccessPolicy;
238
+ owner: {
239
+ configured: boolean;
240
+ id?: string;
241
+ source?: 'account' | 'claim' | 'manual' | 'platform';
242
+ };
243
+ }
244
+ /**
245
+ * Lifecycle phase of a local owner-claim session.
246
+ * - `waiting-message`: a challenge is outstanding; no valid candidate yet.
247
+ * - `candidate`: a valid DM reply carried the exact challenge code.
248
+ * - `confirmed`: the local operator confirmed the candidate (owner persisted).
249
+ * - `expired`: TTL passed before confirmation.
250
+ * - `cancelled`: the local operator cancelled the session.
251
+ */
252
+ export type OwnerClaimPhase = 'waiting-message' | 'candidate' | 'confirmed' | 'expired' | 'cancelled';
253
+ /**
254
+ * Browser-facing owner-claim session. This is the ONLY claim DTO
255
+ * surfaced outside the host. `challengeCode` is a short one-time challenge the
256
+ * local browser shows the operator who then sends it to the bot; it is NOT a
257
+ * platform credential and must never be logged.
258
+ */
259
+ export interface PublicOwnerClaimSession {
260
+ id: string;
261
+ channelId: string;
262
+ accountId: string;
263
+ phase: OwnerClaimPhase;
264
+ /** Short one-time challenge the local browser shows the operator. NOT a credential. */
265
+ challengeCode?: string;
266
+ expiresAt: number;
267
+ candidate?: {
268
+ senderId: string;
269
+ };
270
+ }
271
+ /**
272
+ * Sanitized conversation identity row surfaced to the Web (plan §35). This is
273
+ * display/mapping metadata ONLY: `canonicalId` is the authorization key the
274
+ * policy stores; `externalId`/`displayName` are optional human-facing metadata
275
+ * and must never be written into a policy or consumed by the Access Gate.
276
+ */
277
+ export interface PublicConversationIdentity {
278
+ type: 'group';
279
+ canonicalId: string;
280
+ externalId?: string;
281
+ displayName?: string;
282
+ alias?: string;
283
+ /** The platform identity for this conversation changed at some point (plan §23). */
284
+ identityConflict?: boolean;
285
+ firstSeenAt: number;
286
+ lastSeenAt: number;
287
+ }
288
+ /** Row returned by [ChannelControlService.listChannels] (doc §29). */
289
+ export interface ChannelSummary {
290
+ id: string;
291
+ configured: boolean;
292
+ enabled: boolean;
293
+ mounted: boolean;
294
+ runtime: 'running' | 'stopped';
295
+ connection: 'connected' | 'degraded' | 'disconnected' | 'unknown';
296
+ /** Access readiness of the channel. */
297
+ access: ChannelAccessReadiness;
298
+ }
299
+ /**
300
+ * One channel's setup/authorization/instantiation spec (doc §14). Platform
301
+ * differences stop here: channel-control drives channels purely through this
302
+ * interface, never through per-channel conditionals.
303
+ */
304
+ export interface ChannelDefinition {
305
+ id: string;
306
+ /**
307
+ * Whether the channel is enabled in configuration (doc §29 ChannelSummary.enabled).
308
+ *
309
+ * Implementations MUST expose this as a live getter over their mutable
310
+ * config snapshot (e.g. `get enabled() { return state.enabled }`), never as
311
+ * a registration-time snapshot — the control plane's `setEnabled` reads it
312
+ * again after persisting a change.
313
+ */
314
+ readonly enabled: boolean;
315
+ /**
316
+ * Persist the enabled intent (doc §21). Implementations mutate their
317
+ * config snapshot and push through their durable store (settings scope /
318
+ * credentials seam). The control plane reacts by stopping the runtime when
319
+ * disabled or starting it when re-enabled (doc §22). Optional for
320
+ * definitions that are permanently enabled.
321
+ */
322
+ setEnabled?(enabled: boolean): Promise<void>;
323
+ /** Static setup descriptor (fields + authMethods). */
324
+ setup: ChannelSetupDescriptor;
325
+ /**
326
+ * Dynamic configured state: reads config + credential describe().
327
+ * NEVER returns secret values.
328
+ */
329
+ getConfiguredState(): Promise<ConfiguredState>;
330
+ /**
331
+ * Persist a non-secret config patch. Secret field names are rejected by the
332
+ * control plane before reaching the definition (see saveConfig rules).
333
+ */
334
+ saveConfig(patch: Record<string, unknown>): Promise<void>;
335
+ /**
336
+ * Optional opaque, non-secret fingerprint for the active provider/application
337
+ * scope. Conversation-directory entries are partitioned by this value so a
338
+ * human-facing identifier observed under one Bot/App cannot be resolved
339
+ * after that provider scope changes. It is control-plane bookkeeping only:
340
+ * never returned to the Web and never used for authorization.
341
+ */
342
+ conversationScopeFingerprint?(accountId: string): string | undefined;
343
+ /**
344
+ * Optional host-only snapshot/restore hooks for transactional setup updates.
345
+ * Definitions with mutable config implement both methods so a failed adapter
346
+ * restart can restore the exact prior runtime configuration.
347
+ */
348
+ snapshotConfig?(): unknown;
349
+ restoreConfig?(snapshot: unknown): Promise<void> | void;
350
+ /** Begin an auth session (optional: channels without provider auth omit). */
351
+ beginAuth?(input: AuthBeginInput): Promise<AuthProviderSession>;
352
+ /** Poll a provider session (optional). Receives the SAME AuthProviderSession returned by beginAuth. */
353
+ pollAuth?(session: AuthProviderSession): Promise<PublicAuthStatus>;
354
+ /** Submit auth input (verification code etc.) (optional). */
355
+ submitAuthInput?(session: AuthProviderSession, input: AuthInput): Promise<PublicAuthStatus> | void;
356
+ /** Build the adapter; resolves credentials itself via the injected credentials seam. */
357
+ createAdapter(): Promise<ChannelAdapter>;
358
+ /** Whether this channel should auto-mount when configured (headless, doc §27). Default true. */
359
+ autoStart?: boolean;
360
+ /** Required: declared access capability descriptor. */
361
+ access: ChannelAccessDescriptor;
362
+ /**
363
+ * Only implemented by ownerDiscovery='account' channels. Returns the canonical
364
+ * sender.id of the account owner (e.g. Weixin's scanning QR userId). Never
365
+ * exposes platform storage format to the control plane.
366
+ */
367
+ resolveOwnerIdentity?(accountId: string): Promise<string | undefined>;
368
+ }
369
+ export type { ChannelAdapter, ChannelHealth };
370
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,128 @@
1
+ import type { ChannelStorage } from '@krischoichoi/channel-core';
2
+ /** The bundle package users install (checked on the npm registry). */
3
+ export declare const BUNDLE_PACKAGE = "@krischoichoi/dsh-channels";
4
+ /** Dist-tags consulted by the check (in priority order). */
5
+ export type BundleDistTag = 'latest' | 'next';
6
+ /** Registry fetch timeout (mirrors scripts/check-upstream.mjs). */
7
+ export declare const FETCH_TIMEOUT_MS = 15000;
8
+ /** Durable cache key (versioned so future format changes invalidate old rows). */
9
+ export declare const UPDATE_CHECK_STORAGE_KEY = "update-check:v1";
10
+ /**
11
+ * The installed bundle version. By release convention every runtime-family
12
+ * package (the bundle + its ten dependencies, see docs/release.md) moves in
13
+ * lockstep — each changeset lists the whole family and every package.json
14
+ * carries the same version — so this package's own version IS the installed
15
+ * `@krischoichoi/dsh-channels` version. Keep the family lockstep when bumping;
16
+ * `test/update-check.test.ts` asserts this package's version equals the
17
+ * bundle's.
18
+ */
19
+ export declare const BUNDLE_VERSION: string;
20
+ /** One upgrade command, plus the hint metadata the UI/command plane renders. */
21
+ export interface BundleUpdateInfo {
22
+ /** Target version string, e.g. "0.6.0". */
23
+ version: string;
24
+ /** Which dist-tag provided the target. */
25
+ tag: BundleDistTag;
26
+ /** Target sits on a different major.minor line than the installed bundle. */
27
+ crossLine: boolean;
28
+ /** Advisory upgrade commands in execution order. Nothing is auto-installed. */
29
+ commands: string[];
30
+ }
31
+ /** Sanitized, read-only DTO served to channel-web and the /version command. */
32
+ export interface BundleUpdateStatus {
33
+ /** Installed @krischoichoi/dsh-channels version (workspace lockstep version). */
34
+ currentVersion: string;
35
+ /** Present only when a strictly newer version was found per the tag rules. */
36
+ update?: BundleUpdateInfo;
37
+ /** Epoch ms of the last completed registry check; absent before the first. */
38
+ checkedAt?: number;
39
+ }
40
+ /** Narrow logger seam (satisfied by a Cordis logger; kept structural). */
41
+ export interface UpdateCheckLogger {
42
+ debug(message: string, ...args: unknown[]): void;
43
+ info(message: string, ...args: unknown[]): void;
44
+ }
45
+ export interface BundleUpdateCheckerOptions {
46
+ /** Installed bundle version; defaults to this package's lockstep version. */
47
+ currentVersion?: string;
48
+ /** Whether the check runs at all (config `updateCheck.enabled`). */
49
+ enabled: boolean;
50
+ /** Cache TTL in hours (config `updateCheck.intervalHours`). */
51
+ intervalHours: number;
52
+ /** Lazily resolved durable storage; absent → memory-only caching. */
53
+ getStorage?: () => ChannelStorage | undefined;
54
+ /** Logger for the single info line (update found) and debug diagnostics. */
55
+ logger?: UpdateCheckLogger;
56
+ /** Injectable clock (tests). */
57
+ now?: () => number;
58
+ }
59
+ export interface ParsedSemver {
60
+ major: number;
61
+ minor: number;
62
+ patch: number;
63
+ /** Dot-separated prerelease identifiers; null for a stable release. */
64
+ pre: string[] | null;
65
+ }
66
+ /** Parse a strict semver string, or undefined when malformed. */
67
+ export declare function parseSemver(version: string): ParsedSemver | undefined;
68
+ /** Whether a version string is a legal strict semver (with/without suffixes). */
69
+ export declare function isSemverString(version: string): boolean;
70
+ /**
71
+ * Full semver precedence compare. Build metadata is ignored. Callers must
72
+ * pre-validate inputs with parseSemver; an unparseable side compares equal
73
+ * (never greater), so a malformed value can never fabricate an update hint.
74
+ */
75
+ export declare function compareSemver(a: string, b: string): number;
76
+ /**
77
+ * Evaluate the prompt from dist-tag versions against the installed version.
78
+ * Pure function; malformed versions are ignored (they can never prompt).
79
+ */
80
+ export declare function evaluateBundleUpdate(currentVersion: string, tags: {
81
+ latest?: string;
82
+ next?: string;
83
+ }): BundleUpdateInfo | undefined;
84
+ /**
85
+ * [BundleUpdateChecker] — TTL-cached, offline-tolerant npm dist-tag check.
86
+ * Never throws: every failure path (disabled, offline, timeout, schema
87
+ * rejection, storage error) degrades to "no update known".
88
+ */
89
+ export declare class BundleUpdateChecker {
90
+ private readonly currentVersion;
91
+ private readonly enabled;
92
+ private readonly intervalMs;
93
+ private readonly getStorage;
94
+ private readonly logger;
95
+ private readonly now;
96
+ /** In-memory snapshot so a process reads storage at most once per cache. */
97
+ private memory;
98
+ private inflight;
99
+ constructor(options: BundleUpdateCheckerOptions);
100
+ /**
101
+ * Fire-and-forget check (startup hook). Re-entrant: concurrent callers share
102
+ * one in-flight promise; a fresh cache short-circuits without fetching.
103
+ * Never rejects — callers may `void` it safely.
104
+ */
105
+ trigger(): Promise<void>;
106
+ /**
107
+ * Read-only status for the web control plane / /version command. Returns
108
+ * immediately with the cached snapshot (storage-backed when the process has
109
+ * not checked yet) and kicks a background refresh when the cache is stale
110
+ * or absent — a first request never blocks on the registry.
111
+ */
112
+ getStatus(): Promise<BundleUpdateStatus>;
113
+ private runCheck;
114
+ private isFresh;
115
+ private toStatus;
116
+ /**
117
+ * Fetch the `latest` and `next` single-tag manifests in parallel. The next
118
+ * tag is optional (404 → absent); latest is required for a successful
119
+ * check. Any non-404 failure, and any zod rejection, throws so the whole
120
+ * check is treated as offline (no partially-trusted snapshot is kept).
121
+ */
122
+ private fetchDistTags;
123
+ /** One tag manifest → its version. 404 → undefined (tag not published). */
124
+ private fetchManifestVersion;
125
+ private loadStored;
126
+ private persist;
127
+ }
128
+ //# sourceMappingURL=update-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"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"}