@voltro/kv 0.86.0 → 0.87.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.
- package/CHANGELOG.md +5321 -0
- package/README.md +110 -0
- package/THIRD-PARTY-NOTICES.md +864 -1
- package/dist/analytics.d.ts +337 -0
- package/dist/analytics.js +16 -0
- package/dist/cacheAtomicProtocol.js +247 -0
- package/dist/cacheAtomicScript.js +309 -0
- package/dist/cacheAtomicState.js +141 -0
- package/dist/connection.d.ts +990 -9
- package/dist/connection.js +330 -50
- package/dist/connectionAnalyticsConfig.js +153 -0
- package/dist/connectionConfigProvider.js +111 -0
- package/dist/connectionDefinitions.js +285 -0
- package/dist/connectionMemory.js +207 -0
- package/dist/connectionMetrics.js +79 -0
- package/dist/connectionNamespace.js +19 -0
- package/dist/connectionNats.js +148 -0
- package/dist/connectionNatsConfig.js +87 -0
- package/dist/connectionNatsSubjects.js +16 -0
- package/dist/connectionOwner.js +44 -0
- package/dist/connectionPool.js +738 -0
- package/dist/connectionPrefix.js +37 -0
- package/dist/connectionScripts.js +4 -0
- package/dist/connectionSqlConfig.js +119 -0
- package/dist/connectionStorageConfig.js +190 -0
- package/dist/connectionStorageFacade.js +78 -0
- package/dist/connectionSubscriber.js +130 -0
- package/dist/errors.js +5 -1
- package/dist/hot-contract.d.ts +297 -0
- package/dist/hot-contract.js +18 -0
- package/dist/hot-testing.d.ts +229 -0
- package/dist/hot-testing.js +1 -0
- package/dist/hot.d.ts +936 -0
- package/dist/hot.js +7 -0
- package/dist/hotMemory.js +46 -0
- package/dist/hotOperations.js +223 -0
- package/dist/hotRateLimit.js +103 -0
- package/dist/hotReadAvailability.js +19 -0
- package/dist/hotRedis.js +139 -0
- package/dist/hotRedisScript.js +4 -0
- package/dist/hotRouting.js +78 -0
- package/dist/hotState.js +182 -0
- package/dist/hotStoreConformance.js +367 -0
- package/dist/index.d.ts +113 -9
- package/dist/nativeRedisReads.js +78 -0
- package/dist/nativeRedisTopology.js +221 -0
- package/dist/redisDiagnostics.js +27 -0
- package/dist/redisReadPolicy.js +39 -0
- package/dist/sql.d.ts +77 -0
- package/dist/sql.js +0 -0
- package/dist/storage.d.ts +166 -0
- package/dist/storage.js +48 -0
- package/dist/storageAddress.js +20 -0
- package/package.json +43 -3
package/dist/connection.d.ts
CHANGED
|
@@ -1,12 +1,384 @@
|
|
|
1
|
+
import { CircuitState } from '@voltro/shared';
|
|
1
2
|
import { Config } from 'effect';
|
|
3
|
+
import { ConfigProvider } from 'effect';
|
|
2
4
|
import { Context } from 'effect';
|
|
3
5
|
import { Duration } from 'effect/Duration';
|
|
4
6
|
import { Effect } from 'effect';
|
|
5
7
|
import { Layer } from 'effect';
|
|
6
8
|
import { Schedule } from 'effect';
|
|
7
9
|
import { Schema } from 'effect';
|
|
10
|
+
import { Scope } from 'effect';
|
|
11
|
+
import { SqlClient } from 'effect/sql';
|
|
12
|
+
import { Stream } from 'effect';
|
|
8
13
|
import { YieldableError } from 'effect/Cause';
|
|
9
14
|
|
|
15
|
+
declare interface AggregateQuery {
|
|
16
|
+
readonly event: string;
|
|
17
|
+
readonly filter?: PropertyFilter;
|
|
18
|
+
readonly metric: AnalyticsMetric;
|
|
19
|
+
readonly range: TimeRange;
|
|
20
|
+
/**
|
|
21
|
+
* Restrict the read to one tenant's events. `useAnalytics()` injects the
|
|
22
|
+
* caller's `subject.tenantId` automatically, so handler code never sets
|
|
23
|
+
* this; a sink that honours it (e.g. analytics-postgres) then AND-filters
|
|
24
|
+
* by tenant so a query can't read across tenants. `null`/absent = unscoped
|
|
25
|
+
* (system/cross-tenant read).
|
|
26
|
+
*/
|
|
27
|
+
readonly tenantId?: string | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare interface AnalyticsBucket {
|
|
31
|
+
readonly bucketStart: Date;
|
|
32
|
+
readonly value: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The sink doesn't implement this capability. PostHog returns this
|
|
37
|
+
* for `aggregate`/`timeseries`/`topN`. Callers typically
|
|
38
|
+
* `Effect.catchTag('AnalyticsCapabilityNotSupported', ...)` to fall
|
|
39
|
+
* back to a different sink or report the missing feature.
|
|
40
|
+
*/
|
|
41
|
+
declare class AnalyticsCapabilityNotSupported extends AnalyticsCapabilityNotSupported_base {
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare const AnalyticsCapabilityNotSupported_base: Schema.Class<AnalyticsCapabilityNotSupported, Schema.TaggedStruct<"AnalyticsCapabilityNotSupported", {
|
|
45
|
+
readonly provider: Schema.String;
|
|
46
|
+
readonly capability: Schema.String;
|
|
47
|
+
}>, YieldableError>;
|
|
48
|
+
|
|
49
|
+
declare interface AnalyticsConnectionBatch {
|
|
50
|
+
readonly maxSize?: number;
|
|
51
|
+
readonly flushIntervalMs?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export declare type AnalyticsConnectionConfig = AnalyticsOptions & ConnectionMetadata & {
|
|
55
|
+
readonly source?: 'config' | 'environment' | 'override';
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export declare type AnalyticsConnectionConnector = (config: AnalyticsConnectionConfig) => Effect.Effect<AnalyticsConnectionTransport, KvError>;
|
|
59
|
+
|
|
60
|
+
export declare type AnalyticsConnectionDefinition = DeclareEach<AnalyticsOptions> & ConnectionMetadata;
|
|
61
|
+
|
|
62
|
+
/** Physical transport returned only to the registry, never to a consumer. */
|
|
63
|
+
export declare interface AnalyticsConnectionTransport {
|
|
64
|
+
readonly sink: AnalyticsSinkImpl;
|
|
65
|
+
readonly probe: Effect.Effect<void, KvError>;
|
|
66
|
+
readonly close: Effect.Effect<void>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The underlying sink raised an error. `cause` is stringified for
|
|
71
|
+
* round-trip safety across the rpc boundary.
|
|
72
|
+
*/
|
|
73
|
+
declare class AnalyticsError extends AnalyticsError_base {
|
|
74
|
+
get message(): string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare const AnalyticsError_base: Schema.Class<AnalyticsError, Schema.TaggedStruct<"AnalyticsError", {
|
|
78
|
+
readonly provider: Schema.String;
|
|
79
|
+
readonly operation: Schema.String;
|
|
80
|
+
readonly cause: Schema.String;
|
|
81
|
+
}>, YieldableError>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* One analytics event. `properties` must be JSON-serialisable —
|
|
85
|
+
* individual sinks validate at write time (Postgres stores as JSONB;
|
|
86
|
+
* ClickHouse encodes as a JSON string; PostHog forwards verbatim).
|
|
87
|
+
*/
|
|
88
|
+
declare interface AnalyticsEvent {
|
|
89
|
+
/** Event name (e.g. `'match_completed'`, `'page_viewed'`). */
|
|
90
|
+
readonly name: string;
|
|
91
|
+
/** Subject id (typically `ctx.request.subject.id`) — anonymous when null. */
|
|
92
|
+
readonly subjectId?: string | null;
|
|
93
|
+
/**
|
|
94
|
+
* Owning tenant. Normally you DON'T set this by hand — `useAnalytics()`
|
|
95
|
+
* stamps it from the caller's `subject.tenantId` so every event is
|
|
96
|
+
* tenant-attributable + every read is tenant-scoped (the multi-tenant
|
|
97
|
+
* isolation default). Set it explicitly only for a cross-tenant system
|
|
98
|
+
* write. `null` = no tenant (system/anonymous).
|
|
99
|
+
*/
|
|
100
|
+
readonly tenantId?: string | null;
|
|
101
|
+
/** Property bag. Values must be JSON-serialisable. */
|
|
102
|
+
readonly properties: Readonly<Record<string, unknown>>;
|
|
103
|
+
/** When the event occurred. Defaults to server-now when omitted. */
|
|
104
|
+
readonly occurredAt?: Date;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
declare type AnalyticsFailure = AnalyticsError | AnalyticsCapabilityNotSupported;
|
|
108
|
+
|
|
109
|
+
/** Metric to compute. `count` = row count, `unique` = distinct subjectId,
|
|
110
|
+
* `sum` / `avg` = numeric aggregation on a property field. */
|
|
111
|
+
declare type AnalyticsMetric = 'count' | 'unique' | {
|
|
112
|
+
readonly sum: string;
|
|
113
|
+
} | {
|
|
114
|
+
readonly avg: string;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Optional CDC-mirror capability. A sink that declares `mirror` opts in
|
|
119
|
+
* to receiving the main DataStore's reactive-table changes, so
|
|
120
|
+
* analytical queries can JOIN warehouse events against live user data
|
|
121
|
+
* (`SELECT … FROM voltro_events e JOIN users u ON …`).
|
|
122
|
+
*
|
|
123
|
+
* The framework subscribes to `DataStore.onChange` once at boot, filters
|
|
124
|
+
* to the tables the sink lists in `tables`, and routes each change here.
|
|
125
|
+
* Inserts/updates `upsert` by primary key; deletes `remove`. Every call
|
|
126
|
+
* MUST be idempotent — the same change may be re-delivered after a
|
|
127
|
+
* reconnect, and the upsert is keyed on `primaryKey` so re-applying a
|
|
128
|
+
* row is a no-op-equivalent overwrite.
|
|
129
|
+
*
|
|
130
|
+
* Idempotent is not enough on its own: re-delivery can also arrive OUT
|
|
131
|
+
* OF ORDER, so both methods additionally receive a {@link MirrorVersion}
|
|
132
|
+
* and MUST ignore a write whose version is not greater than the version
|
|
133
|
+
* already stored for that key (ClickHouse gets this from
|
|
134
|
+
* `ReplacingMergeTree(version)`; DuckDB from an `ON CONFLICT … WHERE
|
|
135
|
+
* excluded.version > version` guard).
|
|
136
|
+
*/
|
|
137
|
+
declare interface AnalyticsMirrorImpl {
|
|
138
|
+
/** Reactive tables this sink mirrors. The framework only forwards
|
|
139
|
+
* changes whose `table` is in this set. */
|
|
140
|
+
readonly tables: ReadonlyArray<string>;
|
|
141
|
+
/** Primary-key column the sink upserts/deletes by. Defaults to `'id'`
|
|
142
|
+
* when omitted. */
|
|
143
|
+
readonly primaryKey?: string;
|
|
144
|
+
/** Apply an insert/update. Idempotent upsert keyed on `primaryKey`,
|
|
145
|
+
* version-guarded by `write.version`. */
|
|
146
|
+
readonly upsert: (write: AnalyticsMirrorUpsert) => Effect.Effect<void, AnalyticsFailure>;
|
|
147
|
+
/** Apply a delete. Idempotent — removing an absent key is a no-op —
|
|
148
|
+
* and version-guarded by `write.version`. */
|
|
149
|
+
readonly remove: (write: AnalyticsMirrorRemove) => Effect.Effect<void, AnalyticsFailure>;
|
|
150
|
+
/**
|
|
151
|
+
* The highest version this sink has PERSISTED for one key — `null` when
|
|
152
|
+
* the key has never been written (a tombstoned key still reports its
|
|
153
|
+
* tombstone's version; both warehouse sinks keep tombstones for exactly
|
|
154
|
+
* this reason).
|
|
155
|
+
*
|
|
156
|
+
* This is the fleet-scope seed read: a replica that joins mid-stream has
|
|
157
|
+
* no per-key history of its own, so before its first write to a key it
|
|
158
|
+
* asks the warehouse where the fleet already is and continues from
|
|
159
|
+
* there. Without it a joiner would restart the key's versions low and
|
|
160
|
+
* every write it produced would be silently rejected by the sink's own
|
|
161
|
+
* `version >` guard. Called at most once per key per process (off the
|
|
162
|
+
* commit path, inside the per-key drain worker), never per change.
|
|
163
|
+
*/
|
|
164
|
+
readonly maxVersion: (input: {
|
|
165
|
+
readonly table: string;
|
|
166
|
+
readonly primaryKeyValue: unknown;
|
|
167
|
+
}) => Effect.Effect<MirrorVersion | null, AnalyticsFailure>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** One delete to apply to the mirror. */
|
|
171
|
+
declare interface AnalyticsMirrorRemove {
|
|
172
|
+
readonly table: string;
|
|
173
|
+
/** Primary-key value of the removed row. */
|
|
174
|
+
readonly primaryKeyValue: unknown;
|
|
175
|
+
/** See {@link MirrorVersion}. A delete is ordered against upserts of
|
|
176
|
+
* the same key by exactly this number. */
|
|
177
|
+
readonly version: MirrorVersion;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** One insert/update to apply to the mirror. */
|
|
181
|
+
declare interface AnalyticsMirrorUpsert {
|
|
182
|
+
readonly table: string;
|
|
183
|
+
/** Post-image of the changed row. */
|
|
184
|
+
readonly row: Readonly<Record<string, unknown>>;
|
|
185
|
+
/** See {@link MirrorVersion} — persist it, compare against it, never
|
|
186
|
+
* replace it with a local clock reading. */
|
|
187
|
+
readonly version: MirrorVersion;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
declare type AnalyticsOptions = ({
|
|
191
|
+
readonly provider: 'duckdb';
|
|
192
|
+
readonly path?: string;
|
|
193
|
+
} & MirrorOptions) | ({
|
|
194
|
+
readonly provider: 'clickhouse';
|
|
195
|
+
readonly url: string;
|
|
196
|
+
readonly username?: string;
|
|
197
|
+
readonly password?: string;
|
|
198
|
+
readonly database?: string;
|
|
199
|
+
readonly table?: string;
|
|
200
|
+
readonly batch?: AnalyticsConnectionBatch | false;
|
|
201
|
+
} & MirrorOptions) | {
|
|
202
|
+
readonly provider: 'tinybird';
|
|
203
|
+
readonly token: string;
|
|
204
|
+
readonly apiUrl?: string;
|
|
205
|
+
readonly region?: string;
|
|
206
|
+
readonly datasource?: string;
|
|
207
|
+
readonly pipes?: {
|
|
208
|
+
readonly aggregate?: string;
|
|
209
|
+
readonly timeseries?: string;
|
|
210
|
+
readonly topN?: string;
|
|
211
|
+
};
|
|
212
|
+
} | {
|
|
213
|
+
readonly provider: 'posthog';
|
|
214
|
+
readonly apiKey: string;
|
|
215
|
+
readonly host?: string;
|
|
216
|
+
readonly batch?: AnalyticsConnectionBatch;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The runtime contract every analytics provider implements. Plugins
|
|
221
|
+
* build a value of this shape inside their factory function and the
|
|
222
|
+
* framework wires it under `AnalyticsSink` for handler code to consume.
|
|
223
|
+
*/
|
|
224
|
+
declare interface AnalyticsSinkImpl {
|
|
225
|
+
readonly info: AnalyticsSinkInfo;
|
|
226
|
+
readonly track: (event: AnalyticsEvent) => Effect.Effect<void, AnalyticsFailure>;
|
|
227
|
+
readonly aggregate: (query: AggregateQuery) => Effect.Effect<number, AnalyticsFailure>;
|
|
228
|
+
readonly timeseries: (query: TimeseriesQuery) => Effect.Effect<ReadonlyArray<AnalyticsBucket>, AnalyticsFailure>;
|
|
229
|
+
readonly topN: (query: TopNQuery) => Effect.Effect<ReadonlyArray<AnalyticsTopEntry>, AnalyticsFailure>;
|
|
230
|
+
/**
|
|
231
|
+
* Present when the sink mirrors reactive tables (opt-in via the
|
|
232
|
+
* plugin's `mirrorTables` config). Absent → no mirroring; the
|
|
233
|
+
* framework skips wiring `DataStore.onChange` for this sink.
|
|
234
|
+
*/
|
|
235
|
+
readonly mirror?: AnalyticsMirrorImpl;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Per-sink metadata surfaced via the manifest endpoint + dashboard.
|
|
240
|
+
* Lets the operator see at a glance which provider is wired + what
|
|
241
|
+
* it supports without grepping app.config.ts.
|
|
242
|
+
*/
|
|
243
|
+
declare interface AnalyticsSinkInfo {
|
|
244
|
+
readonly provider: string;
|
|
245
|
+
readonly capabilities: {
|
|
246
|
+
readonly track: boolean;
|
|
247
|
+
readonly aggregate: boolean;
|
|
248
|
+
readonly timeseries: boolean;
|
|
249
|
+
readonly topN: boolean;
|
|
250
|
+
/** True when the sink mirrors reactive tables into the warehouse so
|
|
251
|
+
* analytical queries can JOIN events against live user data. */
|
|
252
|
+
readonly mirror: boolean;
|
|
253
|
+
};
|
|
254
|
+
/** Optional plugin-supplied detail (`{ ingestBufferDepth: 42 }`,
|
|
255
|
+
* `{ url: 'https://eu.posthog.com' }`, etc.) — surfaced verbatim. */
|
|
256
|
+
readonly detail?: Readonly<Record<string, unknown>>;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
declare interface AnalyticsTopEntry {
|
|
260
|
+
readonly key: string;
|
|
261
|
+
readonly value: number;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Select one dynamic definition; tenant identity is passed separately to its resolver. */
|
|
265
|
+
export declare const byTenant: (target: ConnectionRef<"redis">) => ConnectionRoute;
|
|
266
|
+
|
|
267
|
+
declare type ByteStream = Stream.Stream<Uint8Array, StorageError>;
|
|
268
|
+
|
|
269
|
+
/** One cache program. Every accessed key is declared; memberships are versioned. */
|
|
270
|
+
export declare const CACHE_ATOMIC_SCRIPT: string;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* How long an invalidation's epoch stays observable. A compute that runs longer
|
|
274
|
+
* than this can no longer prove no invalidation overtook it, so `Cache.wrap`
|
|
275
|
+
* does not store its result.
|
|
276
|
+
*/
|
|
277
|
+
export declare const CACHE_FENCE_RETENTION_MS = 900000;
|
|
278
|
+
|
|
279
|
+
/** Empty Lua arrays encode as {}; this applies only to known metadata arrays. */
|
|
280
|
+
export declare const cacheAtomicArray: (input: unknown) => ReadonlyArray<unknown>;
|
|
281
|
+
|
|
282
|
+
export declare type CacheAtomicCommand = {
|
|
283
|
+
readonly op: 'revision';
|
|
284
|
+
} | {
|
|
285
|
+
readonly op: 'fence';
|
|
286
|
+
} | {
|
|
287
|
+
readonly op: 'inspect';
|
|
288
|
+
readonly key: string;
|
|
289
|
+
} | {
|
|
290
|
+
readonly op: 'inspect-values';
|
|
291
|
+
readonly keys: ReadonlyArray<string>;
|
|
292
|
+
} | {
|
|
293
|
+
readonly op: 'read';
|
|
294
|
+
readonly key: string;
|
|
295
|
+
readonly snapshot: CacheAtomicSnapshot | null;
|
|
296
|
+
} | {
|
|
297
|
+
readonly op: 'tag';
|
|
298
|
+
readonly tag: string;
|
|
299
|
+
} | {
|
|
300
|
+
readonly op: 'scan';
|
|
301
|
+
readonly cursor: string;
|
|
302
|
+
} | {
|
|
303
|
+
readonly op: 'write';
|
|
304
|
+
readonly key: string;
|
|
305
|
+
readonly snapshot: CacheAtomicSnapshot | null;
|
|
306
|
+
readonly version: string;
|
|
307
|
+
readonly revision: string;
|
|
308
|
+
readonly tags: ReadonlyArray<string>;
|
|
309
|
+
readonly value: string;
|
|
310
|
+
readonly ttlMs: number | null;
|
|
311
|
+
readonly fence: number | null;
|
|
312
|
+
} | {
|
|
313
|
+
readonly op: 'remove';
|
|
314
|
+
readonly key: string;
|
|
315
|
+
readonly snapshot: CacheAtomicSnapshot | null;
|
|
316
|
+
readonly revision: string;
|
|
317
|
+
} | {
|
|
318
|
+
readonly op: 'invalidate';
|
|
319
|
+
readonly tag: string;
|
|
320
|
+
readonly members: ReadonlyArray<string>;
|
|
321
|
+
readonly snapshots: ReadonlyArray<CacheAtomicValueSnapshot>;
|
|
322
|
+
readonly revision: string;
|
|
323
|
+
} | {
|
|
324
|
+
readonly op: 'clear';
|
|
325
|
+
readonly keys: ReadonlyArray<string>;
|
|
326
|
+
readonly revision: string | null;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/** JSON before UTF-8 preserves distinct JS strings containing lone surrogates. */
|
|
330
|
+
export declare const cacheAtomicComponent: (value: string) => string;
|
|
331
|
+
|
|
332
|
+
/** All keys accessed by Lua are declared here, including prior tag memberships. */
|
|
333
|
+
export declare const cacheAtomicKeys: (root: string, command: CacheAtomicCommand) => ReadonlyArray<string>;
|
|
334
|
+
|
|
335
|
+
export declare const cacheAtomicMember: (input: unknown) => {
|
|
336
|
+
readonly version: string;
|
|
337
|
+
readonly key: string;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
/** Replaced values have independent membership identities, never a bare key. */
|
|
341
|
+
export declare const cacheAtomicMembership: (key: string, valueVersion: string) => string;
|
|
342
|
+
|
|
343
|
+
export declare interface CacheAtomicPolicy {
|
|
344
|
+
readonly maxTagMembers?: number;
|
|
345
|
+
readonly maxReplyBytes?: number;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Shared command admission for native cache scripts, local transport and broker. */
|
|
349
|
+
export declare class CacheAtomicProtocolError extends Error {
|
|
350
|
+
constructor();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export declare interface CacheAtomicReply {
|
|
354
|
+
readonly status: 'ok' | 'conflict' | 'limit';
|
|
355
|
+
readonly value: unknown;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Every cache namespace owns one Redis Cluster hash slot. */
|
|
359
|
+
export declare const cacheAtomicRoot: (prefix: string) => string;
|
|
360
|
+
|
|
361
|
+
export declare const cacheAtomicScanPage: (root: string, input: unknown) => {
|
|
362
|
+
readonly cursor: string;
|
|
363
|
+
readonly keys: ReadonlyArray<string>;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
export declare interface CacheAtomicSnapshot {
|
|
367
|
+
readonly version: string;
|
|
368
|
+
readonly tags: ReadonlyArray<string>;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export declare const cacheAtomicSnapshot: (input: unknown) => CacheAtomicSnapshot | null;
|
|
372
|
+
|
|
373
|
+
export declare const cacheAtomicTtl: (ttlMs: number | undefined) => number | null;
|
|
374
|
+
|
|
375
|
+
export declare interface CacheAtomicValueSnapshot {
|
|
376
|
+
readonly key: string;
|
|
377
|
+
readonly snapshot: CacheAtomicSnapshot | null;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export declare const cacheAtomicValueSnapshots: (input: unknown) => ReadonlyArray<CacheAtomicValueSnapshot>;
|
|
381
|
+
|
|
10
382
|
/** Bounded retry for transient command failures (network blip). Connect is
|
|
11
383
|
* NOT retried — a bad url should fail loud at boot. Re-exported so consumers
|
|
12
384
|
* wrap their own command runners consistently. */
|
|
@@ -20,9 +392,256 @@ export declare const commandRetry: Schedule.Schedule< Duration, unknown, never,
|
|
|
20
392
|
*/
|
|
21
393
|
export declare const connect: (config: RedisConnectionConfig) => Effect.Effect<RespClient, KvError>;
|
|
22
394
|
|
|
23
|
-
|
|
395
|
+
/** Resolve an explicit kind:name, a configured default, or the established env convention. */
|
|
396
|
+
export declare function connectionConfig(reference: string): Effect.Effect<RedisConnectionConfig, Config.ConfigError>;
|
|
397
|
+
|
|
398
|
+
export declare function connectionConfig(reference: string, definitions: RedisConnectionsConfig, context?: ConnectionContext): Effect.Effect<RedisConnectionConfig, Config.ConfigError | KvError>;
|
|
399
|
+
|
|
400
|
+
export declare interface ConnectionContext {
|
|
401
|
+
readonly tenantId: string;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** Reject malformed runtime configuration before reading declarations or opening sockets. */
|
|
405
|
+
export declare const connectionDefinitionsProblem: (config: ConnectionsConfig) => string | undefined;
|
|
406
|
+
|
|
407
|
+
/** An environment declaration, never the environment value itself. */
|
|
408
|
+
export declare interface ConnectionEnv {
|
|
409
|
+
readonly _tag: 'ConnectionEnv';
|
|
410
|
+
readonly name: string;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** A connection's kind is part of its reference, so consumers cannot mix ports. */
|
|
414
|
+
export declare type ConnectionKind = 'redis' | 'nats' | 'storage' | 'analytics' | 'sql';
|
|
415
|
+
|
|
416
|
+
export declare interface ConnectionMetadata {
|
|
417
|
+
readonly tls?: 'auto' | 'required';
|
|
418
|
+
readonly persistence?: 'required' | 'optional' | 'none';
|
|
419
|
+
readonly keyPrefix?: string;
|
|
420
|
+
/** Explicit opt-in when a production connection intentionally uses a shared namespace. */
|
|
421
|
+
readonly allowSharedNamespace?: boolean;
|
|
422
|
+
readonly region?: string;
|
|
423
|
+
readonly label?: string;
|
|
424
|
+
readonly acl?: string;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export declare interface ConnectionNamespaceIdentity {
|
|
428
|
+
readonly appName: string;
|
|
429
|
+
readonly environment: string;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export declare interface ConnectionPoolSnapshot {
|
|
433
|
+
readonly reference: string;
|
|
434
|
+
readonly dynamic: boolean;
|
|
435
|
+
readonly activeCommands: number;
|
|
436
|
+
readonly activeSubscriptions: number;
|
|
437
|
+
readonly subscribedChannels: number;
|
|
438
|
+
readonly commands: number;
|
|
439
|
+
readonly errors: number;
|
|
440
|
+
readonly latencyMs: number | null;
|
|
441
|
+
readonly state: CircuitState;
|
|
442
|
+
readonly source: 'config' | 'environment' | 'override';
|
|
443
|
+
readonly label?: string;
|
|
444
|
+
readonly region?: string;
|
|
445
|
+
readonly persistence?: RedisConnectionConfig['persistence'];
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Borrowed Pub/Sub port. A consumer owns registrations, never broker sockets. */
|
|
449
|
+
export declare interface ConnectionPubSub {
|
|
450
|
+
readonly publish: (channel: string, payload: string) => Effect.Effect<void, KvError>;
|
|
451
|
+
readonly subscribe: (channel: string, handler: (payload: string) => void) => Effect.Effect<Effect.Effect<void>, KvError>;
|
|
452
|
+
readonly onTransportEvent: (listener: (event: ConnectionTransportEvent) => void) => () => void;
|
|
453
|
+
readonly close: Effect.Effect<void>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export declare type ConnectionRef<K extends ConnectionKind = ConnectionKind> = `${K}:${string}`;
|
|
457
|
+
|
|
458
|
+
export declare class ConnectionRegistry extends ConnectionRegistry_base {
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
declare const ConnectionRegistry_base: Context.ServiceClass<ConnectionRegistry, "@voltro/ConnectionRegistry", ConnectionRegistryShape>;
|
|
462
|
+
|
|
463
|
+
export declare interface ConnectionRegistryOptions {
|
|
464
|
+
readonly connections?: ConnectionsConfig;
|
|
465
|
+
readonly requirements?: ReadonlyArray<ConnectionRequirement>;
|
|
466
|
+
/** App identity for declared connection namespaces; low-level registries may supply it explicitly. */
|
|
467
|
+
readonly namespaceIdentity?: ConnectionNamespaceIdentity;
|
|
468
|
+
/** Raw driver injection; namespace wrapping belongs to the registry, not the transport. */
|
|
469
|
+
readonly connect?: (config: RedisConnectionConfig) => Effect.Effect<RespClient, KvError>;
|
|
470
|
+
readonly connectStorage?: StorageConnectionConnector;
|
|
471
|
+
readonly connectAnalytics?: AnalyticsConnectionConnector;
|
|
472
|
+
readonly connectSql?: SqlConnectionConnector;
|
|
473
|
+
readonly connectNats?: (config: NatsConnectionConfig) => Effect.Effect<NatsTransport, KvError>;
|
|
474
|
+
readonly connectSubscriber?: (config: RedisConnectionConfig) => Effect.Effect<RespSubscriber, KvError>;
|
|
475
|
+
readonly failureThreshold?: number;
|
|
476
|
+
readonly resetTimeoutMs?: number;
|
|
477
|
+
/** Completed, redacted whole-registry attempts. Observers cannot change admission. */
|
|
478
|
+
readonly onRotation?: (event: ConnectionRotationEvent) => void;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export declare interface ConnectionRegistryShape {
|
|
482
|
+
readonly validate: (reference: ConnectionRef<'redis' | 'nats' | 'storage' | 'analytics' | 'sql'> | '') => Effect.Effect<ConnectionValidation, Config.ConfigError>;
|
|
483
|
+
readonly client: (reference: ConnectionRef<'redis'> | '', context?: ConnectionContext) => Effect.Effect<RespClient, KvError | Config.ConfigError>;
|
|
484
|
+
readonly config: {
|
|
485
|
+
(reference: ConnectionRef<'redis'> | '', context?: ConnectionContext): Effect.Effect<RedisConnectionConfig, Config.ConfigError>;
|
|
486
|
+
(reference: ConnectionRef<'nats'>, context?: ConnectionContext): Effect.Effect<NatsConnectionConfig, Config.ConfigError>;
|
|
487
|
+
(reference: ConnectionRef<'storage'>, context?: ConnectionContext): Effect.Effect<StorageConnectionConfig, Config.ConfigError>;
|
|
488
|
+
(reference: ConnectionRef<'analytics'>, context?: ConnectionContext): Effect.Effect<AnalyticsConnectionConfig, Config.ConfigError>;
|
|
489
|
+
(reference: ConnectionRef<'sql'>, context?: ConnectionContext): Effect.Effect<SqlConnectionConfig, Config.ConfigError>;
|
|
490
|
+
(reference: ConnectionRef<'redis' | 'nats' | 'storage' | 'analytics' | 'sql'> | '', context?: ConnectionContext): Effect.Effect<RedisConnectionConfig | NatsConnectionConfig | StorageConnectionConfig | AnalyticsConnectionConfig | SqlConnectionConfig, Config.ConfigError>;
|
|
491
|
+
};
|
|
492
|
+
readonly sql: (reference: ConnectionRef<'sql'>, context?: ConnectionContext) => Effect.Effect<SqlConnection, KvError | Config.ConfigError>;
|
|
493
|
+
readonly analytics: (reference: ConnectionRef<'analytics'>, context?: ConnectionContext) => Effect.Effect<AnalyticsSinkImpl, KvError | Config.ConfigError>;
|
|
494
|
+
readonly storage: (reference: ConnectionRef<'storage'>, context?: ConnectionContext) => Effect.Effect<StorageProvider, KvError | Config.ConfigError>;
|
|
495
|
+
readonly pubsub: (reference: ConnectionRef<'redis' | 'nats'> | '', context?: ConnectionContext) => Effect.Effect<ConnectionPubSub, KvError | Config.ConfigError>;
|
|
496
|
+
/** Read-only native round trip; never a store write or event publication. */
|
|
497
|
+
readonly probe: (reference: ConnectionRef<'redis' | 'nats' | 'storage' | 'analytics' | 'sql'> | '', context?: ConnectionContext) => Effect.Effect<void, KvError | Config.ConfigError>;
|
|
498
|
+
/** Prepare every replacement, swap atomically, then drain old generations. */
|
|
499
|
+
readonly reload: Effect.Effect<void, KvError | Config.ConfigError>;
|
|
500
|
+
/** Redacted operational metadata: never URLs, credentials or tenant IDs. */
|
|
501
|
+
readonly inspect: Effect.Effect<ReadonlyArray<ConnectionPoolSnapshot>>;
|
|
502
|
+
readonly redis: RespConnections;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export declare interface ConnectionRequirement extends Omit<RedisConnectionRequirement, 'reference'> {
|
|
506
|
+
readonly reference: ConnectionRef<'redis' | 'nats' | 'storage' | 'analytics' | 'sql'> | '';
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export declare interface ConnectionRotationEvent {
|
|
510
|
+
readonly sequence: number;
|
|
511
|
+
readonly startedAt: number;
|
|
512
|
+
readonly durationMs: number;
|
|
513
|
+
readonly outcome: 'succeeded' | 'failed';
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export declare interface ConnectionRoute {
|
|
517
|
+
readonly _tag: 'ConnectionRoute';
|
|
518
|
+
/** Stateful allocation routes cannot address existing keys in a HotStore. */
|
|
519
|
+
readonly keyAffinity?: boolean;
|
|
520
|
+
readonly connections: ReadonlyArray<ConnectionRef<'redis'>>;
|
|
521
|
+
readonly select: (context: {
|
|
522
|
+
readonly key: string;
|
|
523
|
+
readonly tenantId?: string;
|
|
524
|
+
}) => ConnectionRef<'redis'>;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** App registry configuration; protocol-specific command APIs retain their narrower config. */
|
|
528
|
+
export declare interface ConnectionsConfig extends RedisConnectionsConfig {
|
|
529
|
+
readonly nats?: Readonly<Record<string, NatsConnectionDefinition | DynamicNatsConnection>>;
|
|
530
|
+
readonly storage?: Readonly<Record<string, StorageConnectionDefinition | DynamicStorageConnection>>;
|
|
531
|
+
readonly analytics?: Readonly<Record<string, AnalyticsConnectionDefinition | DynamicAnalyticsConnection>>;
|
|
532
|
+
readonly sql?: Readonly<Record<string, SqlConnectionDefinition | DynamicSqlConnection>>;
|
|
533
|
+
readonly defaults?: {
|
|
534
|
+
readonly redis?: string;
|
|
535
|
+
readonly nats?: string;
|
|
536
|
+
readonly storage?: string;
|
|
537
|
+
readonly analytics?: string;
|
|
538
|
+
readonly sql?: string;
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** Physical subscription adapter. Logical consumer ownership belongs to the registry. */
|
|
543
|
+
export declare interface ConnectionSubscriberTransport {
|
|
544
|
+
readonly subscribe: (channel: string) => Promise<void>;
|
|
545
|
+
readonly unsubscribe: (channel: string) => Promise<void>;
|
|
546
|
+
readonly onMessage: (listener: (channel: string, payload: string) => void) => () => void;
|
|
547
|
+
readonly onTransportEvent: (listener: (event: ConnectionTransportEvent) => void) => () => void;
|
|
548
|
+
readonly close: () => Promise<void>;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Facts shared by native broker transports; no broker promises event replay. */
|
|
552
|
+
export declare interface ConnectionTransportEvent {
|
|
553
|
+
readonly kind: 'disconnected' | 'reconnected';
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** Consumers choose an explicit read fallback or preserve an unavailable failure. */
|
|
557
|
+
export declare type ConnectionUnavailablePolicy = 'degrade' | 'fail';
|
|
558
|
+
|
|
559
|
+
/** Declaration admission without resolving tenant-owned credentials or opening a socket. */
|
|
560
|
+
export declare interface ConnectionValidation {
|
|
561
|
+
readonly reference: string;
|
|
562
|
+
readonly tenantScoped: boolean;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Dedicated RESP transport. The registry owns sockets and reconnect attempts.
|
|
566
|
+
* Restore acknowledgements precede reconnected; a gap never promises replay. */
|
|
567
|
+
export declare const connectRedisSubscriber: (config: RedisConnectionConfig) => Effect.Effect<RespSubscriber, KvError>;
|
|
568
|
+
|
|
569
|
+
/** No endpoint, token or resolved tenant credential is part of this manifest. */
|
|
570
|
+
export declare const declaredConnectionEnv: (config: ConnectionsConfig) => ReadonlyArray<string>;
|
|
571
|
+
|
|
572
|
+
declare type DeclareEach<T> = T extends AnalyticsOptions ? DeclareOptions<T> : never;
|
|
573
|
+
|
|
574
|
+
declare type DeclareOptions<T> = {
|
|
575
|
+
readonly [K in keyof T]: K extends 'url' | 'username' | 'password' | 'token' | 'apiUrl' | 'apiKey' | 'host' ? ConnectionEnv | Extract<T[K], undefined> : K extends 'path' ? string | ConnectionEnv | Extract<T[K], undefined> : T[K];
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
export declare const decodeCacheAtomicCommand: (input: unknown) => CacheAtomicCommand;
|
|
579
|
+
|
|
580
|
+
export declare const decodeCacheAtomicPolicy: (input: unknown) => CacheAtomicPolicy;
|
|
581
|
+
|
|
582
|
+
export declare const decodeCacheAtomicReply: (raw: unknown) => CacheAtomicReply;
|
|
583
|
+
|
|
584
|
+
/** Dynamic credentials stay server-side; resolution belongs to the registry scope. */
|
|
585
|
+
export declare const dynamic: (resolve: DynamicRedisConnection["resolve"], options?: {
|
|
586
|
+
readonly ttlMs?: number;
|
|
587
|
+
}) => DynamicRedisConnection;
|
|
588
|
+
|
|
589
|
+
/** Resolve tenant-owned credentials lazily; the registry owns cache and rotation. */
|
|
590
|
+
export declare const dynamicAnalytics: (resolve: DynamicAnalyticsConnection["resolve"], options?: {
|
|
591
|
+
readonly ttlMs?: number;
|
|
592
|
+
}) => DynamicAnalyticsConnection;
|
|
593
|
+
|
|
594
|
+
export declare interface DynamicAnalyticsConnection {
|
|
595
|
+
readonly _tag: 'DynamicAnalyticsConnection';
|
|
596
|
+
readonly resolve: (context: ConnectionContext) => Effect.Effect<AnalyticsConnectionConfig, KvError>;
|
|
597
|
+
readonly ttlMs: number;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/** Tenant-owned NATS credentials, resolved lazily within the app registry. */
|
|
601
|
+
export declare const dynamicNats: (resolve: DynamicNatsConnection["resolve"], options?: {
|
|
602
|
+
readonly ttlMs?: number;
|
|
603
|
+
}) => DynamicNatsConnection;
|
|
604
|
+
|
|
605
|
+
export declare interface DynamicNatsConnection {
|
|
606
|
+
readonly _tag: 'DynamicNatsConnection';
|
|
607
|
+
readonly resolve: (context: ConnectionContext) => Effect.Effect<NatsConnectionConfig, KvError>;
|
|
608
|
+
readonly ttlMs: number;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export declare interface DynamicRedisConnection {
|
|
612
|
+
readonly _tag: 'DynamicRedisConnection';
|
|
613
|
+
readonly resolve: (context: ConnectionContext) => Effect.Effect<RedisConnectionConfig, KvError>;
|
|
614
|
+
readonly ttlMs: number;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** Tenant resolution is lazy and owned by the existing bounded registry. */
|
|
618
|
+
export declare const dynamicSql: (resolve: DynamicSqlConnection["resolve"], options?: {
|
|
619
|
+
readonly ttlMs?: number;
|
|
620
|
+
}) => DynamicSqlConnection;
|
|
621
|
+
|
|
622
|
+
export declare interface DynamicSqlConnection {
|
|
623
|
+
readonly _tag: 'DynamicSqlConnection';
|
|
624
|
+
readonly resolve: (context: ConnectionContext) => Effect.Effect<SqlConnectionConfig, KvError>;
|
|
625
|
+
readonly ttlMs: number;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
export declare const dynamicStorage: (resolve: DynamicStorageConnection["resolve"], options?: {
|
|
629
|
+
readonly ttlMs?: number;
|
|
630
|
+
}) => DynamicStorageConnection;
|
|
631
|
+
|
|
632
|
+
export declare interface DynamicStorageConnection {
|
|
633
|
+
readonly _tag: 'DynamicStorageConnection';
|
|
634
|
+
readonly resolve: (context: ConnectionContext) => Effect.Effect<StorageConnectionConfig, KvError>;
|
|
635
|
+
readonly ttlMs: number;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/** Declare a credential or endpoint without reading it during module import. */
|
|
639
|
+
export declare const env: (name: string) => ConnectionEnv;
|
|
640
|
+
|
|
641
|
+
export declare const isCacheAtomicRead: (command: CacheAtomicCommand) => boolean;
|
|
24
642
|
|
|
25
643
|
declare class KvError extends KvError_base {
|
|
644
|
+
get message(): string;
|
|
26
645
|
}
|
|
27
646
|
|
|
28
647
|
declare const KvError_base: Schema.Class<KvError, Schema.TaggedStruct<"KvError", {
|
|
@@ -35,6 +654,9 @@ declare const KvError_base: Schema.Class<KvError, Schema.TaggedStruct<"KvError",
|
|
|
35
654
|
readonly cause: Schema.String;
|
|
36
655
|
}>, YieldableError>;
|
|
37
656
|
|
|
657
|
+
/** Install the configured registry and its existing command-consumer port together. */
|
|
658
|
+
export declare const layerConfiguredConnections: (options?: ConnectionRegistryOptions) => Layer.Layer<ConnectionRegistry | RedisConnections, Config.ConfigError>;
|
|
659
|
+
|
|
38
660
|
/**
|
|
39
661
|
* `Layer<RedisConnections>` — the pooled registry. Each named connection is
|
|
40
662
|
* opened lazily on first `client(name)`, cached, and closed when the layer's
|
|
@@ -44,14 +666,120 @@ declare const KvError_base: Schema.Class<KvError, Schema.TaggedStruct<"KvError",
|
|
|
44
666
|
*/
|
|
45
667
|
export declare const layerConnections: Layer.Layer<RedisConnections>;
|
|
46
668
|
|
|
47
|
-
|
|
48
|
-
|
|
669
|
+
/** Construct a scoped registry. Even a previously handed-out client follows rotation. */
|
|
670
|
+
export declare const makeConnectionRegistry: (options?: ConnectionRegistryOptions) => Effect.Effect<ConnectionRegistryShape, Config.ConfigError, Scope.Scope>;
|
|
671
|
+
|
|
672
|
+
export declare const memory: (options?: {
|
|
673
|
+
readonly now?: () => number;
|
|
674
|
+
}) => MemoryRedisConnection;
|
|
675
|
+
|
|
676
|
+
/** A local registry entry. Its clock is injectable; it opens no transport. */
|
|
677
|
+
export declare interface MemoryRedisConnection {
|
|
678
|
+
readonly _tag: 'MemoryRedisConnection';
|
|
679
|
+
readonly now?: () => number;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
declare interface MirrorOptions {
|
|
683
|
+
readonly mirrorTables?: ReadonlyArray<string>;
|
|
684
|
+
readonly mirrorPrimaryKey?: string;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Ordering token for one mirrored write.
|
|
689
|
+
*
|
|
690
|
+
* **The sink MUST persist this and MUST NOT invent its own.** It is
|
|
691
|
+
* assigned by the framework at the moment the change leaves the store's
|
|
692
|
+
* change channel — i.e. in COMMIT order — so a write with a lower
|
|
693
|
+
* version is, by construction, an older image of that row. Stamping a
|
|
694
|
+
* version at sink-call time instead (a `Date.now()` inside `upsert`)
|
|
695
|
+
* makes a late-arriving STALE image outrank the fresh one and win
|
|
696
|
+
* permanently; that is the bug this type exists to make unrepresentable.
|
|
697
|
+
*
|
|
698
|
+
* How the number is derived depends on the store's `changeScope`:
|
|
699
|
+
*
|
|
700
|
+
* - `'local'` (one process observes each change): a hybrid clock —
|
|
701
|
+
* wall-clock microseconds forced strictly upward, so it orders within
|
|
702
|
+
* a millisecond and keeps increasing across a restart.
|
|
703
|
+
* - `'fleet'` (every replica observes every change): derived from the
|
|
704
|
+
* CHANGE, not from the receiving process — the warehouse's own max
|
|
705
|
+
* version for the key (read once via {@link AnalyticsMirrorImpl.maxVersion})
|
|
706
|
+
* plus the change's per-key position in the totally-ordered fleet
|
|
707
|
+
* stream. N replicas mirroring the same change therefore stamp the
|
|
708
|
+
* SAME number, and the sink's version guard dedupes the N duplicate
|
|
709
|
+
* writes for free — no leader, no clock, no skew hazard.
|
|
710
|
+
*/
|
|
711
|
+
declare type MirrorVersion = number;
|
|
712
|
+
|
|
713
|
+
export declare interface NatsConnectionConfig extends Omit<ConnectionMetadata, 'persistence'> {
|
|
49
714
|
readonly url: string;
|
|
50
|
-
readonly
|
|
715
|
+
readonly token?: string;
|
|
716
|
+
readonly user?: string;
|
|
717
|
+
readonly pass?: string;
|
|
718
|
+
readonly source?: 'config' | 'environment' | 'override';
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
export declare interface NatsConnectionDefinition extends Omit<ConnectionMetadata, 'persistence'> {
|
|
722
|
+
readonly url: ConnectionEnv;
|
|
723
|
+
readonly token?: ConnectionEnv;
|
|
724
|
+
readonly user?: ConnectionEnv;
|
|
725
|
+
readonly pass?: ConnectionEnv;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/** Physical core-NATS transport. Only registry generations may own this port. */
|
|
729
|
+
export declare interface NatsTransport extends ConnectionSubscriberTransport {
|
|
730
|
+
readonly publish: (subject: string, payload: string) => Promise<void>;
|
|
731
|
+
readonly flush: () => Promise<void>;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
declare interface ObjectMeta {
|
|
735
|
+
readonly size: number;
|
|
736
|
+
readonly etag?: string;
|
|
737
|
+
/** Read-only metadata for lazy, leased streaming reads. */
|
|
738
|
+
readonly contentType?: string;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/** Exact-match property filter. Values are AND'd. */
|
|
742
|
+
declare type PropertyFilter = Readonly<Record<string, string | number | boolean | null>>;
|
|
743
|
+
|
|
744
|
+
export declare interface RedisConnectionConfig extends ConnectionMetadata, RedisTimeouts {
|
|
745
|
+
/** Native Redis, Cluster/Sentinel seed URLs, or the REST URL for HTTP. */
|
|
746
|
+
readonly url: string;
|
|
747
|
+
readonly driver: 'resp' | 'http' | 'memory';
|
|
748
|
+
readonly memoryClock?: () => number;
|
|
51
749
|
/** Auth token — `http` (Upstash REST) driver only. */
|
|
52
750
|
readonly token?: string;
|
|
53
751
|
/** Optional key namespace a deployment may layer its own prefix under. */
|
|
54
|
-
readonly
|
|
752
|
+
readonly cluster?: boolean;
|
|
753
|
+
readonly replicas?: ReadonlyArray<string>;
|
|
754
|
+
readonly readFrom?: 'primary' | 'replica' | 'nearest';
|
|
755
|
+
readonly maxmemoryPolicyHint?: string;
|
|
756
|
+
readonly source?: 'config' | 'environment' | 'override';
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
export declare interface RedisConnectionDefinition extends ConnectionMetadata, RedisTimeouts {
|
|
760
|
+
readonly url: ConnectionEnv;
|
|
761
|
+
readonly driver?: 'resp' | 'http';
|
|
762
|
+
readonly token?: ConnectionEnv;
|
|
763
|
+
readonly cluster?: boolean;
|
|
764
|
+
readonly replicas?: ReadonlyArray<ConnectionEnv>;
|
|
765
|
+
readonly readFrom?: 'primary' | 'replica' | 'nearest';
|
|
766
|
+
readonly maxmemoryPolicyHint?: string;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
export declare interface RedisConnectionDiagnostics {
|
|
770
|
+
/** Every current Cluster primary, or the single standalone/Sentinel primary. */
|
|
771
|
+
readonly nodes: ReadonlyArray<RedisNodeDiagnostics>;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/** Transport admission requirements, attached to the same selected generation as acquisition. */
|
|
775
|
+
export declare interface RedisConnectionRequirement {
|
|
776
|
+
readonly onUnavailable?: ConnectionUnavailablePolicy;
|
|
777
|
+
readonly reference: ConnectionRef<'redis'> | '';
|
|
778
|
+
readonly consumer: string;
|
|
779
|
+
readonly role: string;
|
|
780
|
+
readonly crossNode?: boolean;
|
|
781
|
+
readonly pubsub?: boolean;
|
|
782
|
+
readonly atomicMulti?: boolean;
|
|
55
783
|
}
|
|
56
784
|
|
|
57
785
|
export declare class RedisConnections extends RedisConnections_base {
|
|
@@ -59,11 +787,46 @@ export declare class RedisConnections extends RedisConnections_base {
|
|
|
59
787
|
|
|
60
788
|
declare const RedisConnections_base: Context.ServiceClass<RedisConnections, "@voltro/RedisConnections", RespConnections>;
|
|
61
789
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
790
|
+
export declare interface RedisConnectionsConfig {
|
|
791
|
+
readonly redis?: Readonly<Record<string, RedisConnectionDefinition | DynamicRedisConnection | MemoryRedisConnection>>;
|
|
792
|
+
readonly defaults?: {
|
|
793
|
+
readonly redis?: string;
|
|
794
|
+
};
|
|
795
|
+
/** App-owned selection by plugin name and declared role; plugins never choose endpoints. */
|
|
796
|
+
readonly bindings?: Readonly<Record<string, Readonly<Record<string, ConnectionRef>>>>;
|
|
797
|
+
readonly maxDynamicPools?: number;
|
|
798
|
+
readonly rotationGraceMs?: number;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/** Only enumerated server settings leave the transport; never raw INFO/errors. */
|
|
802
|
+
export declare interface RedisNodeDiagnostics {
|
|
803
|
+
readonly persistence: 'aof' | 'snapshot' | 'none' | 'unknown';
|
|
804
|
+
readonly maxmemoryPolicy: 'noeviction' | 'allkeys-lru' | 'allkeys-lfu' | 'allkeys-random' | 'volatile-lru' | 'volatile-lfu' | 'volatile-random' | 'volatile-ttl' | 'unknown';
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/** A consumer owns its registrations; closing it never closes shared sockets. */
|
|
808
|
+
export declare interface RedisPubSub extends ConnectionPubSub {
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/** Optional native RESP transport deadlines in integer milliseconds. */
|
|
812
|
+
export declare interface RedisTimeouts {
|
|
813
|
+
/** TCP/TLS connection establishment limit; does not prove command completion. */
|
|
814
|
+
readonly connectTimeoutMs?: number;
|
|
815
|
+
/** Limit for a command reply. A write may still complete after this expires. */
|
|
816
|
+
readonly commandTimeoutMs?: number;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
export declare interface RedisTransportEvent extends ConnectionTransportEvent {
|
|
820
|
+
}
|
|
821
|
+
|
|
66
822
|
export declare interface RespClient {
|
|
823
|
+
readonly readOnly?: RespReadClient;
|
|
824
|
+
/** False for a local test connection. PING never turns it into a network backend. */
|
|
825
|
+
readonly crossNode?: boolean;
|
|
826
|
+
/** Read-only round-trip probe. Custom drivers may omit it; no readiness is inferred. */
|
|
827
|
+
readonly ping?: () => Promise<string>;
|
|
828
|
+
/** Explicit read-only server-settings observation. Missing/denied fields stay unknown. */
|
|
829
|
+
readonly diagnostics?: () => Promise<RedisConnectionDiagnostics>;
|
|
67
830
|
readonly get: (key: string) => Promise<string | null>;
|
|
68
831
|
readonly set: (key: string, value: string) => Promise<unknown>;
|
|
69
832
|
readonly psetex: (key: string, ms: number, value: string) => Promise<unknown>;
|
|
@@ -75,6 +838,8 @@ export declare interface RespClient {
|
|
|
75
838
|
readonly cursor: string;
|
|
76
839
|
readonly keys: ReadonlyArray<string>;
|
|
77
840
|
}>;
|
|
841
|
+
/** Native command transport is ready again after reconnect. Registry-owned. */
|
|
842
|
+
readonly onReconnect?: (listener: () => void) => () => void;
|
|
78
843
|
readonly close: () => Promise<void>;
|
|
79
844
|
}
|
|
80
845
|
|
|
@@ -88,4 +853,220 @@ export declare interface RespConnections {
|
|
|
88
853
|
readonly config: (name: string) => Effect.Effect<RedisConnectionConfig, Config.ConfigError>;
|
|
89
854
|
}
|
|
90
855
|
|
|
856
|
+
/** The minimal command surface both ioredis and @upstash/redis satisfy —
|
|
857
|
+
* the superset the framework's command-only RESP consumers (cache, rate
|
|
858
|
+
* limiter, KV) need. `eval` runs a Lua script server-side (numKeys splits
|
|
859
|
+
* KEYS from ARGV, the ioredis convention); `zrange` reads a full sorted set. */
|
|
860
|
+
/** Read-only commands. Native and HTTP Lua use EVAL_RO, never writable EVAL. */
|
|
861
|
+
export declare interface RespReadClient {
|
|
862
|
+
readonly get: (key: string) => Promise<string | null>;
|
|
863
|
+
readonly exists: (key: string) => Promise<number>;
|
|
864
|
+
readonly zrange: (key: string) => Promise<ReadonlyArray<string>>;
|
|
865
|
+
readonly eval: (script: string, numKeys: number, ...args: ReadonlyArray<string | number>) => Promise<unknown>;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/** Dedicated RESP subscriber transport. Only the connection registry owns it. */
|
|
869
|
+
export declare interface RespSubscriber extends ConnectionSubscriberTransport {
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/** Round-robin is for independent staging keys, never a distributed key's identity. */
|
|
873
|
+
export declare const roundRobin: (targets: ReadonlyArray<ConnectionRef<"redis">>) => ConnectionRoute;
|
|
874
|
+
|
|
875
|
+
/** A stable, explicitly keyed shard mapping; changing its targets requires a rebuild. */
|
|
876
|
+
export declare const shardBy: (options: {
|
|
877
|
+
readonly key: (key: string) => string;
|
|
878
|
+
readonly to: ReadonlyArray<ConnectionRef<"redis">>;
|
|
879
|
+
}) => ConnectionRoute;
|
|
880
|
+
|
|
881
|
+
/** A whole operation (including its transaction) borrows one physical generation.
|
|
882
|
+
* Do not return the client, a deferred statement or a stream from use: execute it
|
|
883
|
+
* inside the callback. Use stream for a lazy result that must retain its lease. */
|
|
884
|
+
export declare interface SqlConnection {
|
|
885
|
+
readonly dialect: SqlConnectionConfig['dialect'];
|
|
886
|
+
readonly use: <A, E, R>(run: (client: SqlClient.SqlClient) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | KvError | Config.ConfigError, R>;
|
|
887
|
+
readonly stream: <A, E, R>(run: (client: SqlClient.SqlClient) => Stream.Stream<A, E, R>) => Stream.Stream<A, E | KvError | Config.ConfigError, R>;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/** Additional SQL target. The primary DataStore retains its own configuration. */
|
|
891
|
+
export declare interface SqlConnectionConfig {
|
|
892
|
+
readonly dialect: SqlConnectionDialect;
|
|
893
|
+
readonly url: string;
|
|
894
|
+
readonly tls?: 'auto' | 'required';
|
|
895
|
+
readonly maxConnections?: number;
|
|
896
|
+
readonly acquireTimeoutMs?: number;
|
|
897
|
+
readonly acquireQueueLimit?: number;
|
|
898
|
+
readonly statementTimeoutMs?: number;
|
|
899
|
+
readonly schema?: string;
|
|
900
|
+
readonly label?: string;
|
|
901
|
+
readonly region?: string;
|
|
902
|
+
readonly source?: 'config' | 'override';
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
export declare type SqlConnectionConnector = (config: SqlConnectionConfig) => Effect.Effect<SqlConnectionTransport, KvError>;
|
|
906
|
+
|
|
907
|
+
export declare interface SqlConnectionDefinition extends Omit<SqlConnectionConfig, 'url' | 'source'> {
|
|
908
|
+
readonly url: ConnectionEnv;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
declare type SqlConnectionDialect = 'postgres' | 'mysql' | 'mariadb' | 'mssql' | 'sqlite' | 'turso';
|
|
912
|
+
|
|
913
|
+
/** Connector-owned resources; a consumer never receives physical disposal. */
|
|
914
|
+
export declare interface SqlConnectionTransport {
|
|
915
|
+
readonly client: SqlClient.SqlClient;
|
|
916
|
+
readonly probe: Effect.Effect<void, KvError>;
|
|
917
|
+
readonly close: Effect.Effect<void>;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/** Resolved values stay server-side and never enter inspection snapshots. */
|
|
921
|
+
export declare interface StorageConnectionConfig extends ConnectionMetadata {
|
|
922
|
+
readonly provider: StorageProviderName;
|
|
923
|
+
readonly bucket?: string;
|
|
924
|
+
readonly root?: string;
|
|
925
|
+
readonly endpoint?: string;
|
|
926
|
+
readonly accessKeyId?: string;
|
|
927
|
+
readonly secretAccessKey?: string;
|
|
928
|
+
readonly accountName?: string;
|
|
929
|
+
readonly accountKey?: string;
|
|
930
|
+
readonly connectionString?: string;
|
|
931
|
+
readonly cdnBaseUrl?: string;
|
|
932
|
+
readonly forcePathStyle?: boolean;
|
|
933
|
+
readonly publicAcl?: boolean;
|
|
934
|
+
readonly source?: 'config' | 'environment' | 'override';
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
export declare type StorageConnectionConnector = (config: StorageConnectionConfig, context: StorageConnectionOpenContext) => Effect.Effect<StorageConnectionTransport, StorageError>;
|
|
938
|
+
|
|
939
|
+
export declare interface StorageConnectionDefinition extends ConnectionMetadata {
|
|
940
|
+
readonly provider: StorageProviderName;
|
|
941
|
+
readonly bucket?: string | ConnectionEnv;
|
|
942
|
+
readonly root?: string | ConnectionEnv;
|
|
943
|
+
readonly endpoint?: ConnectionEnv;
|
|
944
|
+
readonly accessKeyId?: ConnectionEnv;
|
|
945
|
+
readonly secretAccessKey?: ConnectionEnv;
|
|
946
|
+
readonly accountName?: string | ConnectionEnv;
|
|
947
|
+
readonly accountKey?: ConnectionEnv;
|
|
948
|
+
readonly connectionString?: ConnectionEnv;
|
|
949
|
+
readonly cdnBaseUrl?: string | ConnectionEnv;
|
|
950
|
+
readonly forcePathStyle?: boolean;
|
|
951
|
+
readonly publicAcl?: boolean;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
declare interface StorageConnectionOpenContext {
|
|
955
|
+
/** Local state belongs to this registry identity, preserved across physical rotation. */
|
|
956
|
+
readonly memory?: Map<string, StoredObject>;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** A transport is created lazily; only the registry owns its physical disposal. */
|
|
960
|
+
export declare interface StorageConnectionTransport {
|
|
961
|
+
readonly provider: StorageProvider;
|
|
962
|
+
readonly probe: Effect.Effect<void, StorageError>;
|
|
963
|
+
readonly close: Effect.Effect<void>;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** The object transport error, shared with the storage plugin's wire contract. */
|
|
967
|
+
declare class StorageError extends StorageError_base {
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
declare const StorageError_base: Schema.Class<StorageError, Schema.TaggedStruct<"StorageError", {
|
|
971
|
+
readonly provider: Schema.String;
|
|
972
|
+
readonly message: Schema.String;
|
|
973
|
+
readonly transient: Schema.Boolean;
|
|
974
|
+
readonly status: Schema.optional<Schema.Number>;
|
|
975
|
+
/** Cleanup was not confirmed; inspect the destination before another write. */
|
|
976
|
+
readonly outcome: Schema.optional<Schema.Literal<"unknown">>;
|
|
977
|
+
}>, YieldableError>;
|
|
978
|
+
|
|
979
|
+
/** Server-side physical identity; never serialize a namespace into inspection. */
|
|
980
|
+
declare interface StorageObjectLocation {
|
|
981
|
+
readonly namespace: string | object;
|
|
982
|
+
readonly key: string;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/** Opaque keyed bytes; policy and durable references belong to the plugin. */
|
|
986
|
+
export declare interface StorageProvider {
|
|
987
|
+
/** Stable, credential-independent SHA-256 identity of this physical key namespace. */
|
|
988
|
+
readonly objectNamespace: Effect.Effect<string, StorageError>;
|
|
989
|
+
/** Canonical container and physical key, including connection prefixes. */
|
|
990
|
+
readonly objectLocation?: (key: string) => Effect.Effect<StorageObjectLocation, StorageError>;
|
|
991
|
+
readonly root?: string;
|
|
992
|
+
readonly name: string;
|
|
993
|
+
readonly presigns: boolean;
|
|
994
|
+
readonly put: (key: string, bytes: Uint8Array, meta: {
|
|
995
|
+
readonly contentType: string;
|
|
996
|
+
readonly public?: boolean;
|
|
997
|
+
}) => Effect.Effect<ObjectMeta, StorageError>;
|
|
998
|
+
readonly get: (key: string) => Effect.Effect<StoredObject, StorageError>;
|
|
999
|
+
readonly delete: (key: string) => Effect.Effect<void, StorageError>;
|
|
1000
|
+
readonly getUrl: (key: string, expiresInSec: number) => Effect.Effect<string, StorageError>;
|
|
1001
|
+
readonly publicUrl?: (key: string) => string | null;
|
|
1002
|
+
readonly setObjectPublic?: (key: string, isPublic: boolean) => Effect.Effect<void, StorageError>;
|
|
1003
|
+
readonly getUploadUrl?: (key: string, expiresInSec: number, contentType: string) => Effect.Effect<string, StorageError>;
|
|
1004
|
+
readonly createMultipartUpload?: (key: string, contentType: string, opts?: {
|
|
1005
|
+
readonly public?: boolean;
|
|
1006
|
+
}) => Effect.Effect<{
|
|
1007
|
+
readonly uploadId: string;
|
|
1008
|
+
}, StorageError>;
|
|
1009
|
+
readonly presignUploadPart?: (key: string, uploadId: string, partNumber: number, expiresInSec: number) => Effect.Effect<string, StorageError>;
|
|
1010
|
+
readonly completeMultipartUpload?: (key: string, uploadId: string, parts: ReadonlyArray<{
|
|
1011
|
+
readonly partNumber: number;
|
|
1012
|
+
readonly etag: string;
|
|
1013
|
+
}>) => Effect.Effect<{
|
|
1014
|
+
readonly etag?: string;
|
|
1015
|
+
}, StorageError>;
|
|
1016
|
+
readonly abortMultipartUpload?: (key: string, uploadId: string) => Effect.Effect<void, StorageError>;
|
|
1017
|
+
readonly head: (key: string) => Effect.Effect<ObjectMeta | null, StorageError>;
|
|
1018
|
+
readonly getStream?: (key: string) => Effect.Effect<StoredStream, StorageError>;
|
|
1019
|
+
readonly putStream?: (key: string, stream: ByteStream, meta: {
|
|
1020
|
+
readonly contentType: string;
|
|
1021
|
+
readonly public?: boolean;
|
|
1022
|
+
readonly totalSize?: number;
|
|
1023
|
+
}) => Effect.Effect<ObjectMeta, StorageError>;
|
|
1024
|
+
readonly getRange?: (key: string, start: number, endInclusive: number) => Effect.Effect<Uint8Array, StorageError>;
|
|
1025
|
+
readonly bindDataStore?: (store: unknown) => void;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
declare type StorageProviderName = 's3' | 'minio' | 'azure' | 'filesystem' | 'memory' | 'database';
|
|
1029
|
+
|
|
1030
|
+
declare interface StoredObject {
|
|
1031
|
+
readonly bytes: Uint8Array;
|
|
1032
|
+
readonly contentType: string;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
declare interface StoredStream {
|
|
1036
|
+
readonly stream: ByteStream;
|
|
1037
|
+
readonly contentType: string;
|
|
1038
|
+
readonly size?: number;
|
|
1039
|
+
/** Release an opened body even if cancellation precedes its first pull. */
|
|
1040
|
+
readonly close?: Effect.Effect<void>;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
declare type TimeBucket = 'minute' | 'hour' | 'day' | 'week' | 'month';
|
|
1044
|
+
|
|
1045
|
+
/** Time window. `to` defaults to now. */
|
|
1046
|
+
declare interface TimeRange {
|
|
1047
|
+
readonly from: Date;
|
|
1048
|
+
readonly to?: Date;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
declare interface TimeseriesQuery extends AggregateQuery {
|
|
1052
|
+
readonly bucket: TimeBucket;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
declare interface TopNQuery {
|
|
1056
|
+
readonly event: string;
|
|
1057
|
+
/** Property to group by (must be a string-valued property). */
|
|
1058
|
+
readonly groupBy: string;
|
|
1059
|
+
readonly metric: 'count' | {
|
|
1060
|
+
readonly sum: string;
|
|
1061
|
+
};
|
|
1062
|
+
readonly n: number;
|
|
1063
|
+
readonly range: TimeRange;
|
|
1064
|
+
readonly filter?: PropertyFilter;
|
|
1065
|
+
/** Tenant scope — injected by `useAnalytics()`; see {@link AggregateQuery.tenantId}. */
|
|
1066
|
+
readonly tenantId?: string | null;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/** Preserve operator and tenant configuration when borrowed Effects cross runtimes. */
|
|
1070
|
+
export declare const withConnectionRegistryConfigProvider: (registry: ConnectionRegistryShape, provider: ConfigProvider.ConfigProvider) => ConnectionRegistryShape;
|
|
1071
|
+
|
|
91
1072
|
export { }
|