@enterstellar-ai/adapters 0.1.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/LICENSE +196 -0
- package/NOTICE +17 -0
- package/README.md +181 -0
- package/dist/index.cjs +323 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +769 -0
- package/dist/index.d.ts +769 -0
- package/dist/index.js +307 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
import { AuthAdapter, DataAdapter, ErrorAdapter, AnalyticsAdapter, EnterstellarError } from '@enterstellar-ai/types';
|
|
2
|
+
export { AnalyticsAdapter, AuthAdapter, DataAdapter, ErrorAdapter } from '@enterstellar-ai/types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @module @enterstellar-ai/adapters/types
|
|
6
|
+
* @description Module-local configuration types for adapter factories.
|
|
7
|
+
*
|
|
8
|
+
* These types define the "input" shape that consumers pass to
|
|
9
|
+
* `createAuthAdapter()`, `createDataAdapter()`, etc. The actual adapter
|
|
10
|
+
* interfaces (`AuthAdapter`, `DataAdapter`, `ErrorAdapter`, `AnalyticsAdapter`)
|
|
11
|
+
* live in `@enterstellar-ai/types/adapters` and are re-exported from the barrel.
|
|
12
|
+
*
|
|
13
|
+
* Each config type mirrors its corresponding adapter interface, plus a
|
|
14
|
+
* mandatory `name` field for identification in error messages and DevTools.
|
|
15
|
+
*
|
|
16
|
+
* @see Bible §4.15
|
|
17
|
+
* @see Design Choices AD1–AD5
|
|
18
|
+
* @see Design Choice T1 — interfaces for behavior, types for data shapes
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Configuration for {@link createAuthAdapter}.
|
|
22
|
+
*
|
|
23
|
+
* The consumer provides their implementation of each method. The factory
|
|
24
|
+
* validates the config and wraps each method to catch errors → `EnterstellarError`
|
|
25
|
+
* per Design Choice AD5.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const auth = createAuthAdapter({
|
|
30
|
+
* name: 'supabase-auth',
|
|
31
|
+
* getSession: async () => {
|
|
32
|
+
* const { data } = await supabase.auth.getSession();
|
|
33
|
+
* if (!data.session) return null;
|
|
34
|
+
* return { userId: data.session.user.id, roles: ['clinician'] };
|
|
35
|
+
* },
|
|
36
|
+
* hasRole: async (role) => {
|
|
37
|
+
* const session = await supabase.auth.getSession();
|
|
38
|
+
* return session.data.session?.user.role === role;
|
|
39
|
+
* },
|
|
40
|
+
* onAuthChange: (cb) => {
|
|
41
|
+
* const { data } = supabase.auth.onAuthStateChange((_event, session) => {
|
|
42
|
+
* cb(session ? { userId: session.user.id, roles: ['clinician'] } : null);
|
|
43
|
+
* });
|
|
44
|
+
* return () => data.subscription.unsubscribe();
|
|
45
|
+
* },
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
type AuthAdapterConfig = {
|
|
50
|
+
/**
|
|
51
|
+
* Human-readable adapter name for error messages and DevTools display.
|
|
52
|
+
*
|
|
53
|
+
* @example `'supabase-auth'`, `'clerk-auth'`, `'firebase-auth'`
|
|
54
|
+
*/
|
|
55
|
+
readonly name: string;
|
|
56
|
+
/**
|
|
57
|
+
* Returns the current authentication session, or `null` if unauthenticated.
|
|
58
|
+
*
|
|
59
|
+
* @returns Session object with user ID and role list.
|
|
60
|
+
*/
|
|
61
|
+
readonly getSession: () => Promise<{
|
|
62
|
+
userId: string;
|
|
63
|
+
roles: string[];
|
|
64
|
+
} | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Checks whether the current user has a specific role.
|
|
67
|
+
* Essential for RBAC — clinical vs. admin zone visibility.
|
|
68
|
+
*
|
|
69
|
+
* @param role - The role to check (e.g., `'clinician'`, `'admin'`).
|
|
70
|
+
* @returns `true` if the user has the specified role.
|
|
71
|
+
*/
|
|
72
|
+
readonly hasRole: (role: string) => Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Subscribes to authentication state changes.
|
|
75
|
+
*
|
|
76
|
+
* Essential for reactive auth gating — zones re-evaluate visibility
|
|
77
|
+
* when sessions expire or roles change.
|
|
78
|
+
*
|
|
79
|
+
* @param callback - Called when auth state changes. Receives the new
|
|
80
|
+
* session object, or `null` if the user became unauthenticated.
|
|
81
|
+
* @returns An unsubscribe function (synchronous).
|
|
82
|
+
*/
|
|
83
|
+
readonly onAuthChange: (callback: (session: {
|
|
84
|
+
userId: string;
|
|
85
|
+
roles: string[];
|
|
86
|
+
} | null) => void) => () => void;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Configuration for {@link createDataAdapter}.
|
|
90
|
+
*
|
|
91
|
+
* Resolves abstract data source names (e.g., `'patients.vitals'`) to actual
|
|
92
|
+
* data using convention-based dot-notation resolution (AD3).
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const data = createDataAdapter({
|
|
97
|
+
* name: 'supabase-data',
|
|
98
|
+
* query: async (resource, params) => {
|
|
99
|
+
* const { data } = await supabase.from(resource).select('*').match(params ?? {});
|
|
100
|
+
* return data ?? [];
|
|
101
|
+
* },
|
|
102
|
+
* mutate: async (resource, action, payload) => {
|
|
103
|
+
* if (action === 'create') {
|
|
104
|
+
* const { data } = await supabase.from(resource).insert(payload).select().single();
|
|
105
|
+
* return data;
|
|
106
|
+
* }
|
|
107
|
+
* return null;
|
|
108
|
+
* },
|
|
109
|
+
* subscribe: (resource, callback) => {
|
|
110
|
+
* const channel = supabase.channel(resource)
|
|
111
|
+
* .on('postgres_changes', { event: '*', schema: 'public', table: resource },
|
|
112
|
+
* () => { void query(resource).then(callback); })
|
|
113
|
+
* .subscribe();
|
|
114
|
+
* return () => { void supabase.removeChannel(channel); };
|
|
115
|
+
* },
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
type DataAdapterConfig = {
|
|
120
|
+
/**
|
|
121
|
+
* Human-readable adapter name for error messages and DevTools display.
|
|
122
|
+
*
|
|
123
|
+
* @example `'supabase-data'`, `'firebase-data'`, `'prisma-data'`
|
|
124
|
+
*/
|
|
125
|
+
readonly name: string;
|
|
126
|
+
/**
|
|
127
|
+
* Queries a resource by name with optional parameters.
|
|
128
|
+
*
|
|
129
|
+
* @param resource - The resource/table/collection to query (dot-notation per AD3).
|
|
130
|
+
* @param params - Optional query parameters (filters, pagination, sorting).
|
|
131
|
+
* @returns Array of records matching the query.
|
|
132
|
+
*/
|
|
133
|
+
readonly query: (resource: string, params?: Readonly<Record<string, unknown>>) => Promise<readonly Record<string, unknown>[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Performs a mutation (create, update, delete) on a resource.
|
|
136
|
+
*
|
|
137
|
+
* @param resource - The resource to mutate.
|
|
138
|
+
* @param action - The mutation type: `'create'`, `'update'`, or `'delete'`.
|
|
139
|
+
* @param data - The mutation payload.
|
|
140
|
+
* @returns The mutated record, or `null` for deletes.
|
|
141
|
+
*/
|
|
142
|
+
readonly mutate: (resource: string, action: 'create' | 'update' | 'delete', data: Readonly<Record<string, unknown>>) => Promise<Record<string, unknown> | null>;
|
|
143
|
+
/**
|
|
144
|
+
* Subscribes to real-time changes on a resource.
|
|
145
|
+
* Essential for live data updates in Enterstellar zones (AD4 — realtime at v1).
|
|
146
|
+
*
|
|
147
|
+
* @param resource - The resource to subscribe to.
|
|
148
|
+
* @param callback - Called when the resource changes.
|
|
149
|
+
* @returns An unsubscribe function (synchronous).
|
|
150
|
+
*/
|
|
151
|
+
readonly subscribe: (resource: string, callback: (data: readonly Record<string, unknown>[]) => void) => () => void;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Configuration for {@link createErrorAdapter}.
|
|
155
|
+
*
|
|
156
|
+
* Implementations provide retry logic, error reporting, and PII sanitization.
|
|
157
|
+
* All methods are async per AD2 — `shouldRetry` and `sanitize` support
|
|
158
|
+
* production use cases such as remote circuit breaker checks and external
|
|
159
|
+
* PII detection services. Raw vendor errors are wrapped into `EnterstellarError`
|
|
160
|
+
* per AD5.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const errors = createErrorAdapter({
|
|
165
|
+
* name: 'sentry-error',
|
|
166
|
+
* report: async (error, context) => {
|
|
167
|
+
* Sentry.captureException(error, { extra: context });
|
|
168
|
+
* },
|
|
169
|
+
* shouldRetry: async (error, attempt) => attempt < 3 && isTransient(error),
|
|
170
|
+
* sanitize: async (error) => {
|
|
171
|
+
* const sanitized = new Error(error.message.replace(/\d{3}-\d{2}-\d{4}/g, '[REDACTED]'));
|
|
172
|
+
* sanitized.stack = error.stack;
|
|
173
|
+
* return sanitized;
|
|
174
|
+
* },
|
|
175
|
+
* });
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
type ErrorAdapterConfig = {
|
|
179
|
+
/**
|
|
180
|
+
* Human-readable adapter name for error messages and DevTools display.
|
|
181
|
+
*
|
|
182
|
+
* @example `'sentry-error'`, `'datadog-error'`, `'console-error'`
|
|
183
|
+
*/
|
|
184
|
+
readonly name: string;
|
|
185
|
+
/**
|
|
186
|
+
* Reports an error to the external error tracking service.
|
|
187
|
+
*
|
|
188
|
+
* @param error - The error to report (may be an `EnterstellarError`).
|
|
189
|
+
* @param context - Optional contextual metadata for the error report.
|
|
190
|
+
*/
|
|
191
|
+
readonly report: (error: Error, context?: Readonly<Record<string, unknown>>) => Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Determines whether a failed operation should be retried.
|
|
194
|
+
*
|
|
195
|
+
* Async to support production implementations that consult remote
|
|
196
|
+
* circuit breakers or rate-limit services before deciding.
|
|
197
|
+
*
|
|
198
|
+
* @param error - The error that caused the failure.
|
|
199
|
+
* @param attemptNumber - The current retry attempt (1-based).
|
|
200
|
+
* @returns `true` if the operation should be retried.
|
|
201
|
+
*/
|
|
202
|
+
readonly shouldRetry: (error: Error, attemptNumber: number) => Promise<boolean>;
|
|
203
|
+
/**
|
|
204
|
+
* Sanitizes an error before it is logged or displayed.
|
|
205
|
+
* Must strip any PII or sensitive data from the error message and stack.
|
|
206
|
+
*
|
|
207
|
+
* Async to support production implementations that call external
|
|
208
|
+
* PII detection services for HIPAA-compliant sanitization.
|
|
209
|
+
*
|
|
210
|
+
* @param error - The error to sanitize.
|
|
211
|
+
* @returns A sanitized copy of the error.
|
|
212
|
+
*/
|
|
213
|
+
readonly sanitize: (error: Error) => Promise<Error>;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Configuration for {@link createAnalyticsAdapter}.
|
|
217
|
+
*
|
|
218
|
+
* Implementations forward user interaction events and identity to analytics
|
|
219
|
+
* services. Both methods are fire-and-forget (void return).
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* const analytics = createAnalyticsAdapter({
|
|
224
|
+
* name: 'mixpanel-analytics',
|
|
225
|
+
* track: (event, properties) => {
|
|
226
|
+
* mixpanel.track(event, properties);
|
|
227
|
+
* },
|
|
228
|
+
* identify: (userId, traits) => {
|
|
229
|
+
* mixpanel.identify(userId);
|
|
230
|
+
* if (traits) mixpanel.people.set(traits);
|
|
231
|
+
* },
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
type AnalyticsAdapterConfig = {
|
|
236
|
+
/**
|
|
237
|
+
* Human-readable adapter name for error messages and DevTools display.
|
|
238
|
+
*
|
|
239
|
+
* @example `'mixpanel-analytics'`, `'amplitude-analytics'`, `'posthog-analytics'`
|
|
240
|
+
*/
|
|
241
|
+
readonly name: string;
|
|
242
|
+
/**
|
|
243
|
+
* Tracks a named event with optional properties.
|
|
244
|
+
* Fire-and-forget — no return value.
|
|
245
|
+
*
|
|
246
|
+
* @param event - The event name (e.g., `'zone_rendered'`, `'intent_resolved'`).
|
|
247
|
+
* @param properties - Optional event properties for segmentation.
|
|
248
|
+
*/
|
|
249
|
+
readonly track: (event: string, properties?: Readonly<Record<string, unknown>>) => void;
|
|
250
|
+
/**
|
|
251
|
+
* Identifies the current user for analytics attribution.
|
|
252
|
+
* Fire-and-forget — no return value.
|
|
253
|
+
*
|
|
254
|
+
* @param userId - Unique user identifier.
|
|
255
|
+
* @param traits - Optional user traits (role, plan, etc.).
|
|
256
|
+
*/
|
|
257
|
+
readonly identify: (userId: string, traits?: Readonly<Record<string, unknown>>) => void;
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* Discriminated adapter type name.
|
|
261
|
+
* Used by {@link validateAdapterConfig} to determine which fields to validate.
|
|
262
|
+
*/
|
|
263
|
+
type AdapterType = 'auth' | 'data' | 'error' | 'analytics';
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @module @enterstellar-ai/adapters/create-auth-adapter
|
|
267
|
+
* @description Factory functions for creating validated `AuthAdapter` instances.
|
|
268
|
+
*
|
|
269
|
+
* - `createAuthAdapter(config)` — wraps a consumer-provided implementation,
|
|
270
|
+
* validates config via {@link validateAdapterConfig}, and wraps every method
|
|
271
|
+
* in error handling per Design Choice AD5 (raw vendor errors never leak).
|
|
272
|
+
*
|
|
273
|
+
* - `createNoopAuthAdapter()` — returns a no-op adapter for testing and
|
|
274
|
+
* development when no real auth provider is connected.
|
|
275
|
+
*
|
|
276
|
+
* Both factories return a plain object with closures (R1 pattern — no classes).
|
|
277
|
+
*
|
|
278
|
+
* @see Bible §4.15
|
|
279
|
+
* @see Design Choice AD1 — minimal but complete: getSession, hasRole, onAuthChange
|
|
280
|
+
* @see Design Choice AD2 — always async (I/O methods)
|
|
281
|
+
* @see Design Choice AD5 — wrap into EnterstellarError
|
|
282
|
+
*/
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Creates a validated `AuthAdapter` from consumer-provided config.
|
|
286
|
+
*
|
|
287
|
+
* The factory:
|
|
288
|
+
* 1. Validates the config (name + required methods) — throws `ENS-7001` on failure.
|
|
289
|
+
* 2. Wraps `getSession()` and `hasRole()` in error handling → `ENS-7005` on throw.
|
|
290
|
+
* 3. Wraps `onAuthChange()` in error handling → `ENS-7002` on throw.
|
|
291
|
+
*
|
|
292
|
+
* Consumers never see raw vendor errors — all failures are `EnterstellarError` (AD5).
|
|
293
|
+
*
|
|
294
|
+
* @param config - The adapter implementation with a `name` and all required methods.
|
|
295
|
+
* @returns A frozen `AuthAdapter` instance.
|
|
296
|
+
* @throws `EnterstellarError` with code `ENS-7001` if config validation fails.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* import { createAuthAdapter } from '@enterstellar-ai/adapters';
|
|
301
|
+
*
|
|
302
|
+
* const auth = createAuthAdapter({
|
|
303
|
+
* name: 'supabase-auth',
|
|
304
|
+
* getSession: async () => {
|
|
305
|
+
* const { data } = await supabase.auth.getSession();
|
|
306
|
+
* if (!data.session) return null;
|
|
307
|
+
* return { userId: data.session.user.id, roles: ['clinician'] };
|
|
308
|
+
* },
|
|
309
|
+
* hasRole: async (role) => {
|
|
310
|
+
* const session = await supabase.auth.getSession();
|
|
311
|
+
* return session.data.session?.user.role === role;
|
|
312
|
+
* },
|
|
313
|
+
* onAuthChange: (cb) => {
|
|
314
|
+
* const { data } = supabase.auth.onAuthStateChange((_event, session) => {
|
|
315
|
+
* cb(session ? { userId: session.user.id, roles: ['clinician'] } : null);
|
|
316
|
+
* });
|
|
317
|
+
* return () => data.subscription.unsubscribe();
|
|
318
|
+
* },
|
|
319
|
+
* });
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare function createAuthAdapter(config: AuthAdapterConfig): AuthAdapter;
|
|
323
|
+
/**
|
|
324
|
+
* Creates a no-op `AuthAdapter` for testing and development.
|
|
325
|
+
*
|
|
326
|
+
* All methods resolve to safe defaults:
|
|
327
|
+
* - `getSession()` → `null` (unauthenticated)
|
|
328
|
+
* - `hasRole()` → `false` (no permissions)
|
|
329
|
+
* - `onAuthChange()` → no-op unsubscribe function (never fires)
|
|
330
|
+
*
|
|
331
|
+
* @returns A frozen, no-op `AuthAdapter` instance.
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* import { createNoopAuthAdapter } from '@enterstellar-ai/adapters';
|
|
336
|
+
*
|
|
337
|
+
* const auth = createNoopAuthAdapter();
|
|
338
|
+
* await auth.getSession(); // null
|
|
339
|
+
* await auth.hasRole('admin'); // false
|
|
340
|
+
* const unsub = auth.onAuthChange(() => {}); // never called
|
|
341
|
+
* unsub(); // no-op
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
declare function createNoopAuthAdapter(): AuthAdapter;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @module @enterstellar-ai/adapters/create-data-adapter
|
|
348
|
+
* @description Factory functions for creating validated `DataAdapter` instances.
|
|
349
|
+
*
|
|
350
|
+
* - `createDataAdapter(config)` — wraps a consumer-provided implementation,
|
|
351
|
+
* validates config via {@link validateAdapterConfig}, and wraps every method
|
|
352
|
+
* in error handling per Design Choice AD5 (raw vendor errors never leak).
|
|
353
|
+
*
|
|
354
|
+
* - `createNoopDataAdapter()` — returns a no-op adapter for testing and
|
|
355
|
+
* development when no real data source is connected.
|
|
356
|
+
*
|
|
357
|
+
* Both factories return a plain object with closures (R1 pattern — no classes).
|
|
358
|
+
*
|
|
359
|
+
* @see Bible §4.15
|
|
360
|
+
* @see Design Choice AD1 — minimal but complete: query, mutate, subscribe
|
|
361
|
+
* @see Design Choice AD2 — always async (except subscribe's sync unsubscribe return)
|
|
362
|
+
* @see Design Choice AD3 — convention-based dot-notation resolver
|
|
363
|
+
* @see Design Choice AD5 — wrap into EnterstellarError
|
|
364
|
+
*/
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Creates a validated `DataAdapter` from consumer-provided config.
|
|
368
|
+
*
|
|
369
|
+
* The factory:
|
|
370
|
+
* 1. Validates the config (name + required methods) — throws `ENS-7001` on failure.
|
|
371
|
+
* 2. Wraps `query()` in error handling → `ENS-7003` on throw (includes resource name).
|
|
372
|
+
* 3. Wraps `mutate()` in error handling → `ENS-7004` on throw (includes resource + action).
|
|
373
|
+
* 4. Wraps `subscribe()` in error handling → `ENS-7002` on throw (generic method error).
|
|
374
|
+
*
|
|
375
|
+
* Consumers never see raw vendor errors — all failures are `EnterstellarError` (AD5).
|
|
376
|
+
*
|
|
377
|
+
* @param config - The adapter implementation with a `name` and all required methods.
|
|
378
|
+
* @returns A frozen `DataAdapter` instance.
|
|
379
|
+
* @throws `EnterstellarError` with code `ENS-7001` if config validation fails.
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* ```ts
|
|
383
|
+
* import { createDataAdapter } from '@enterstellar-ai/adapters';
|
|
384
|
+
*
|
|
385
|
+
* const data = createDataAdapter({
|
|
386
|
+
* name: 'supabase-data',
|
|
387
|
+
* query: async (resource, params) => {
|
|
388
|
+
* const { data } = await supabase.from(resource).select('*').match(params ?? {});
|
|
389
|
+
* return data ?? [];
|
|
390
|
+
* },
|
|
391
|
+
* mutate: async (resource, action, payload) => {
|
|
392
|
+
* if (action === 'create') {
|
|
393
|
+
* const { data } = await supabase.from(resource).insert(payload).select().single();
|
|
394
|
+
* return data;
|
|
395
|
+
* }
|
|
396
|
+
* return null;
|
|
397
|
+
* },
|
|
398
|
+
* subscribe: (resource, callback) => {
|
|
399
|
+
* const channel = supabase.channel(resource)
|
|
400
|
+
* .on('postgres_changes', { event: '*', schema: 'public', table: resource },
|
|
401
|
+
* () => { data.query(resource).then(callback); })
|
|
402
|
+
* .subscribe();
|
|
403
|
+
* return () => { void supabase.removeChannel(channel); };
|
|
404
|
+
* },
|
|
405
|
+
* });
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
declare function createDataAdapter(config: DataAdapterConfig): DataAdapter;
|
|
409
|
+
/**
|
|
410
|
+
* Creates a no-op `DataAdapter` for testing and development.
|
|
411
|
+
*
|
|
412
|
+
* All methods resolve to safe defaults:
|
|
413
|
+
* - `query()` → `[]` (empty result set)
|
|
414
|
+
* - `mutate()` → `null` (no record returned)
|
|
415
|
+
* - `subscribe()` → no-op unsubscribe function
|
|
416
|
+
*
|
|
417
|
+
* @returns A frozen, no-op `DataAdapter` instance.
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* import { createNoopDataAdapter } from '@enterstellar-ai/adapters';
|
|
422
|
+
*
|
|
423
|
+
* const data = createNoopDataAdapter();
|
|
424
|
+
* await data.query('patients.vitals'); // []
|
|
425
|
+
* await data.mutate('patients', 'create', { name: 'Test' }); // null
|
|
426
|
+
* const unsub = data.subscribe('patients', () => {}); // noop unsub
|
|
427
|
+
* unsub(); // no-op
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
declare function createNoopDataAdapter(): DataAdapter;
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @module @enterstellar-ai/adapters/create-error-adapter
|
|
434
|
+
* @description Factory functions for creating validated `ErrorAdapter` instances.
|
|
435
|
+
*
|
|
436
|
+
* - `createErrorAdapter(config)` — wraps a consumer-provided implementation,
|
|
437
|
+
* validates config via {@link validateAdapterConfig}, and wraps every method
|
|
438
|
+
* in error handling per Design Choice AD5 (raw vendor errors never leak).
|
|
439
|
+
*
|
|
440
|
+
* - `createNoopErrorAdapter()` — returns a no-op adapter for testing and
|
|
441
|
+
* development when no real error tracking service is connected.
|
|
442
|
+
*
|
|
443
|
+
* Both factories return a plain object with closures (R1 pattern — no classes).
|
|
444
|
+
*
|
|
445
|
+
* @see Bible §4.15
|
|
446
|
+
* @see Design Choice AD2 — all methods async (I/O + future-proofing)
|
|
447
|
+
* @see Design Choice AD5 — wrap into EnterstellarError
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Creates a validated `ErrorAdapter` from consumer-provided config.
|
|
452
|
+
*
|
|
453
|
+
* The factory:
|
|
454
|
+
* 1. Validates the config (name + required methods) — throws `ENS-7001` on failure.
|
|
455
|
+
* 2. Wraps `report()` in async error handling → `ENS-7002` on throw.
|
|
456
|
+
* 3. Wraps `shouldRetry()` in async error handling → `ENS-7002` on throw.
|
|
457
|
+
* 4. Wraps `sanitize()` in async error handling → `ENS-7002` on throw.
|
|
458
|
+
*
|
|
459
|
+
* All three methods are async per AD2 — even `shouldRetry` and `sanitize`
|
|
460
|
+
* which may seem synchronous in simple implementations, but production
|
|
461
|
+
* adapters may require remote circuit breaker checks or external PII
|
|
462
|
+
* detection services.
|
|
463
|
+
*
|
|
464
|
+
* Consumers never see raw vendor errors — all failures are `EnterstellarError` (AD5).
|
|
465
|
+
*
|
|
466
|
+
* @param config - The adapter implementation with a `name` and all required methods.
|
|
467
|
+
* @returns A frozen `ErrorAdapter` instance.
|
|
468
|
+
* @throws `EnterstellarError` with code `ENS-7001` if config validation fails.
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```ts
|
|
472
|
+
* import { createErrorAdapter } from '@enterstellar-ai/adapters';
|
|
473
|
+
*
|
|
474
|
+
* const errors = createErrorAdapter({
|
|
475
|
+
* name: 'sentry-error',
|
|
476
|
+
* report: async (error, context) => {
|
|
477
|
+
* Sentry.captureException(error, { extra: context });
|
|
478
|
+
* },
|
|
479
|
+
* shouldRetry: async (error, attempt) => attempt < 3 && isTransient(error),
|
|
480
|
+
* sanitize: async (error) => {
|
|
481
|
+
* const sanitized = new Error(error.message.replace(/SSN-\d+/g, '[REDACTED]'));
|
|
482
|
+
* sanitized.stack = error.stack;
|
|
483
|
+
* return sanitized;
|
|
484
|
+
* },
|
|
485
|
+
* });
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
declare function createErrorAdapter(config: ErrorAdapterConfig): ErrorAdapter;
|
|
489
|
+
/**
|
|
490
|
+
* Creates a no-op `ErrorAdapter` for testing and development.
|
|
491
|
+
*
|
|
492
|
+
* All methods resolve to safe defaults:
|
|
493
|
+
* - `report()` → void (errors silently consumed)
|
|
494
|
+
* - `shouldRetry()` → `false` (never retry)
|
|
495
|
+
* - `sanitize()` → returns error as-is (no transformation)
|
|
496
|
+
*
|
|
497
|
+
* @returns A frozen, no-op `ErrorAdapter` instance.
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```ts
|
|
501
|
+
* import { createNoopErrorAdapter } from '@enterstellar-ai/adapters';
|
|
502
|
+
*
|
|
503
|
+
* const errors = createNoopErrorAdapter();
|
|
504
|
+
* await errors.report(new Error('test')); // no-op
|
|
505
|
+
* await errors.shouldRetry(new Error('test'), 1); // false
|
|
506
|
+
* await errors.sanitize(new Error('test')); // returns same error
|
|
507
|
+
* ```
|
|
508
|
+
*/
|
|
509
|
+
declare function createNoopErrorAdapter(): ErrorAdapter;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* @module @enterstellar-ai/adapters/create-analytics-adapter
|
|
513
|
+
* @description Factory functions for creating validated `AnalyticsAdapter` instances.
|
|
514
|
+
*
|
|
515
|
+
* - `createAnalyticsAdapter(config)` — wraps a consumer-provided implementation,
|
|
516
|
+
* validates config via {@link validateAdapterConfig}, and wraps every method
|
|
517
|
+
* in error handling per Design Choice AD5 (raw vendor errors never leak).
|
|
518
|
+
*
|
|
519
|
+
* - `createNoopAnalyticsAdapter()` — returns a no-op adapter for testing and
|
|
520
|
+
* development when no real analytics service is connected.
|
|
521
|
+
*
|
|
522
|
+
* Both factories return a plain object with closures (R1 pattern — no classes).
|
|
523
|
+
*
|
|
524
|
+
* @see Bible §4.15
|
|
525
|
+
* @see Design Choice AD1 — minimal but complete: track, identify
|
|
526
|
+
* @see Design Choice AD5 — wrap into EnterstellarError
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Creates a validated `AnalyticsAdapter` from consumer-provided config.
|
|
531
|
+
*
|
|
532
|
+
* The factory:
|
|
533
|
+
* 1. Validates the config (name + required methods) — throws `ENS-7001` on failure.
|
|
534
|
+
* 2. Wraps `track()` in sync error handling → `ENS-7002` on throw.
|
|
535
|
+
* 3. Wraps `identify()` in sync error handling → `ENS-7002` on throw.
|
|
536
|
+
*
|
|
537
|
+
* Both `track()` and `identify()` are fire-and-forget (void return).
|
|
538
|
+
* Consumers never see raw vendor errors — all failures are `EnterstellarError` (AD5).
|
|
539
|
+
*
|
|
540
|
+
* @param config - The adapter implementation with a `name` and all required methods.
|
|
541
|
+
* @returns A frozen `AnalyticsAdapter` instance.
|
|
542
|
+
* @throws `EnterstellarError` with code `ENS-7001` if config validation fails.
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* ```ts
|
|
546
|
+
* import { createAnalyticsAdapter } from '@enterstellar-ai/adapters';
|
|
547
|
+
*
|
|
548
|
+
* const analytics = createAnalyticsAdapter({
|
|
549
|
+
* name: 'mixpanel-analytics',
|
|
550
|
+
* track: (event, properties) => {
|
|
551
|
+
* mixpanel.track(event, properties);
|
|
552
|
+
* },
|
|
553
|
+
* identify: (userId, traits) => {
|
|
554
|
+
* mixpanel.identify(userId);
|
|
555
|
+
* if (traits) mixpanel.people.set(traits);
|
|
556
|
+
* },
|
|
557
|
+
* });
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
declare function createAnalyticsAdapter(config: AnalyticsAdapterConfig): AnalyticsAdapter;
|
|
561
|
+
/**
|
|
562
|
+
* Creates a no-op `AnalyticsAdapter` for testing and development.
|
|
563
|
+
*
|
|
564
|
+
* All methods are silent no-ops:
|
|
565
|
+
* - `track()` → void (events silently consumed)
|
|
566
|
+
* - `identify()` → void (identity silently consumed)
|
|
567
|
+
*
|
|
568
|
+
* @returns A frozen, no-op `AnalyticsAdapter` instance.
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```ts
|
|
572
|
+
* import { createNoopAnalyticsAdapter } from '@enterstellar-ai/adapters';
|
|
573
|
+
*
|
|
574
|
+
* const analytics = createNoopAnalyticsAdapter();
|
|
575
|
+
* analytics.track('zone_rendered', { zone: 'main' }); // no-op
|
|
576
|
+
* analytics.identify('user-123', { role: 'clinician' }); // no-op
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
579
|
+
declare function createNoopAnalyticsAdapter(): AnalyticsAdapter;
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* @module @enterstellar-ai/adapters/errors
|
|
583
|
+
* @description Error factory functions for the adapters module.
|
|
584
|
+
*
|
|
585
|
+
* Every error is an `EnterstellarError` with:
|
|
586
|
+
* - Machine-readable `code` (`ENS-7xxx`)
|
|
587
|
+
* - Module identifier `'adapters'`
|
|
588
|
+
* - `recoverable` flag per Enterstellar error taxonomy
|
|
589
|
+
*
|
|
590
|
+
* Error taxonomy:
|
|
591
|
+
* - `ENS-7001` — ADAPTER_VALIDATION_FAILED: config missing required methods or invalid name
|
|
592
|
+
* (non-recoverable, developer misconfiguration)
|
|
593
|
+
* - `ENS-7002` — ADAPTER_METHOD_ERROR: adapter method threw during execution (recoverable)
|
|
594
|
+
* - `ENS-7003` — ADAPTER_QUERY_ERROR: DataAdapter query() failed (recoverable)
|
|
595
|
+
* - `ENS-7004` — ADAPTER_MUTATION_ERROR: DataAdapter mutate() failed (recoverable)
|
|
596
|
+
* - `ENS-7005` — ADAPTER_AUTH_ERROR: AuthAdapter session/role check failed (recoverable)
|
|
597
|
+
*
|
|
598
|
+
* @see Coding Rules — Error Taxonomy
|
|
599
|
+
* @see Design Choice AD5 — wrap into EnterstellarError
|
|
600
|
+
* @see Design Choice C14 — error code ranges
|
|
601
|
+
*/
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Creates an error for when an adapter config fails validation.
|
|
605
|
+
*
|
|
606
|
+
* This is a **non-recoverable** error — it indicates developer misconfiguration
|
|
607
|
+
* (missing required methods, empty name, non-function fields). The consumer
|
|
608
|
+
* must fix their adapter config before proceeding.
|
|
609
|
+
*
|
|
610
|
+
* @param adapterType - The adapter category that failed validation (e.g., `'auth'`, `'data'`).
|
|
611
|
+
* @param reason - Human-readable explanation of what is invalid.
|
|
612
|
+
* @returns An `EnterstellarError` with code `ENS-7001`.
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* throw adapterValidationError('auth', 'Missing required method: getSession');
|
|
617
|
+
* // EnterstellarError: Adapter validation failed for "auth": Missing required method: getSession
|
|
618
|
+
* // code: 'ENS-7001', module: 'adapters', recoverable: false
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
declare function adapterValidationError(adapterType: AdapterType, reason: string): EnterstellarError;
|
|
622
|
+
/**
|
|
623
|
+
* Creates an error for when an adapter method throws during execution.
|
|
624
|
+
*
|
|
625
|
+
* This is a **recoverable** error — the underlying infrastructure may have
|
|
626
|
+
* experienced a transient failure. The operation can be retried. The original
|
|
627
|
+
* error is preserved in `cause` for debugging (AD5).
|
|
628
|
+
*
|
|
629
|
+
* @param adapterName - The adapter instance name (e.g., `'supabase-auth'`).
|
|
630
|
+
* @param methodName - The method that threw (e.g., `'getSession'`, `'track'`).
|
|
631
|
+
* @param cause - The original error thrown by the adapter implementation.
|
|
632
|
+
* @returns An `EnterstellarError` with code `ENS-7002`.
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* throw adapterMethodError('supabase-auth', 'getSession', originalError);
|
|
637
|
+
* // EnterstellarError: Adapter "supabase-auth" method "getSession" threw.
|
|
638
|
+
* // code: 'ENS-7002', module: 'adapters', recoverable: true, cause: originalError
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
declare function adapterMethodError(adapterName: string, methodName: string, cause?: unknown): EnterstellarError;
|
|
642
|
+
/**
|
|
643
|
+
* Creates an error for when a {@link DataAdapter}'s `query()` method fails.
|
|
644
|
+
*
|
|
645
|
+
* This is a **recoverable** error — the data source may be temporarily
|
|
646
|
+
* unavailable. Specialized variant of `ENS-7002` that includes the
|
|
647
|
+
* queried resource name for debugging.
|
|
648
|
+
*
|
|
649
|
+
* @param adapterName - The adapter instance name (e.g., `'supabase-data'`).
|
|
650
|
+
* @param resource - The resource that was being queried (e.g., `'patients.vitals'`).
|
|
651
|
+
* @param cause - The original error thrown by the query implementation.
|
|
652
|
+
* @returns An `EnterstellarError` with code `ENS-7003`.
|
|
653
|
+
*
|
|
654
|
+
* @example
|
|
655
|
+
* ```ts
|
|
656
|
+
* throw adapterQueryError('supabase-data', 'patients.vitals', pgError);
|
|
657
|
+
* // EnterstellarError: Adapter "supabase-data" query failed for resource "patients.vitals".
|
|
658
|
+
* // code: 'ENS-7003', module: 'adapters', recoverable: true, cause: pgError
|
|
659
|
+
* ```
|
|
660
|
+
*/
|
|
661
|
+
declare function adapterQueryError(adapterName: string, resource: string, cause?: unknown): EnterstellarError;
|
|
662
|
+
/**
|
|
663
|
+
* Creates an error for when a {@link DataAdapter}'s `mutate()` method fails.
|
|
664
|
+
*
|
|
665
|
+
* This is a **recoverable** error — the data source may be temporarily
|
|
666
|
+
* unavailable. Specialized variant of `ENS-7002` that includes the
|
|
667
|
+
* resource name and mutation action for debugging.
|
|
668
|
+
*
|
|
669
|
+
* @param adapterName - The adapter instance name (e.g., `'supabase-data'`).
|
|
670
|
+
* @param resource - The resource being mutated (e.g., `'patients'`).
|
|
671
|
+
* @param action - The mutation action that failed (`'create'`, `'update'`, or `'delete'`).
|
|
672
|
+
* @param cause - The original error thrown by the mutation implementation.
|
|
673
|
+
* @returns An `EnterstellarError` with code `ENS-7004`.
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* ```ts
|
|
677
|
+
* throw adapterMutationError('supabase-data', 'patients', 'update', pgError);
|
|
678
|
+
* // EnterstellarError: Adapter "supabase-data" mutation "update" failed for resource "patients".
|
|
679
|
+
* // code: 'ENS-7004', module: 'adapters', recoverable: true, cause: pgError
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
declare function adapterMutationError(adapterName: string, resource: string, action: 'create' | 'update' | 'delete', cause?: unknown): EnterstellarError;
|
|
683
|
+
/**
|
|
684
|
+
* Creates an error for when an {@link AuthAdapter}'s session or role check fails.
|
|
685
|
+
*
|
|
686
|
+
* This is a **recoverable** error — the auth provider may be temporarily
|
|
687
|
+
* unavailable, or the session may have expired. Specialized variant of
|
|
688
|
+
* `ENS-7002` for authentication operations.
|
|
689
|
+
*
|
|
690
|
+
* @param adapterName - The adapter instance name (e.g., `'clerk-auth'`).
|
|
691
|
+
* @param operation - The auth operation that failed (e.g., `'getSession'`, `'hasRole'`).
|
|
692
|
+
* @param cause - The original error thrown by the auth implementation.
|
|
693
|
+
* @returns An `EnterstellarError` with code `ENS-7005`.
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```ts
|
|
697
|
+
* throw adapterAuthError('clerk-auth', 'getSession', sessionExpiredError);
|
|
698
|
+
* // EnterstellarError: Adapter "clerk-auth" auth operation "getSession" failed.
|
|
699
|
+
* // code: 'ENS-7005', module: 'adapters', recoverable: true, cause: sessionExpiredError
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
declare function adapterAuthError(adapterName: string, operation: string, cause?: unknown): EnterstellarError;
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* @module @enterstellar-ai/adapters/validate-adapter
|
|
706
|
+
* @description Shared runtime validation for adapter configuration objects.
|
|
707
|
+
*
|
|
708
|
+
* Called by each `createXxxAdapter()` factory before wrapping the consumer's
|
|
709
|
+
* implementation. Validates that:
|
|
710
|
+
* - The config has a non-empty `name` string
|
|
711
|
+
* - All required methods for the adapter type are present and are functions
|
|
712
|
+
*
|
|
713
|
+
* Throws `ENS-7001` (`adapterValidationError`) on any violation — this is a
|
|
714
|
+
* non-recoverable developer error per Enterstellar error taxonomy.
|
|
715
|
+
*
|
|
716
|
+
* @see Coding Rules — Error Taxonomy (developer errors → fatal throw)
|
|
717
|
+
* @see Design Choice AD1 — minimal but complete interfaces
|
|
718
|
+
*/
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Validates that an adapter config object has a valid name and all required methods.
|
|
722
|
+
*
|
|
723
|
+
* This function performs two checks:
|
|
724
|
+
* 1. **Name check:** `config.name` must be a non-empty string.
|
|
725
|
+
* 2. **Method check:** Every method listed in {@link REQUIRED_METHODS} for the
|
|
726
|
+
* given `adapterType` must be present on the config and be `typeof === 'function'`.
|
|
727
|
+
*
|
|
728
|
+
* Throws `ENS-7001` on the first validation failure encountered.
|
|
729
|
+
*
|
|
730
|
+
* @param adapterType - The adapter category being validated (e.g., `'auth'`, `'data'`).
|
|
731
|
+
* @param config - The raw config object to validate.
|
|
732
|
+
* @throws `EnterstellarError` with code `ENS-7001` if validation fails.
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* ```ts
|
|
736
|
+
* // Valid — passes silently
|
|
737
|
+
* validateAdapterConfig('auth', {
|
|
738
|
+
* name: 'supabase-auth',
|
|
739
|
+
* getSession: async () => null,
|
|
740
|
+
* hasRole: async () => false,
|
|
741
|
+
* onAuthChange: (cb) => () => {},
|
|
742
|
+
* });
|
|
743
|
+
*
|
|
744
|
+
* // Invalid — throws ENS-7001
|
|
745
|
+
* validateAdapterConfig('auth', { name: '', getSession: null });
|
|
746
|
+
* // EnterstellarError: Adapter validation failed for "auth": "name" must be a non-empty string.
|
|
747
|
+
* ```
|
|
748
|
+
*/
|
|
749
|
+
declare function validateAdapterConfig(adapterType: AdapterType, config: Readonly<Record<string, unknown>>): void;
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* @module @enterstellar-ai/adapters/version
|
|
753
|
+
* @description Package version constant for `@enterstellar-ai/adapters`.
|
|
754
|
+
*
|
|
755
|
+
* Used by DevTools for version display and runtime compatibility checks.
|
|
756
|
+
* Must be kept in sync with the `version` field in `package.json`.
|
|
757
|
+
*
|
|
758
|
+
* @see Design Choice T14 — version exports
|
|
759
|
+
*/
|
|
760
|
+
/**
|
|
761
|
+
* Current version of the `@enterstellar-ai/adapters` package.
|
|
762
|
+
*
|
|
763
|
+
* @remarks
|
|
764
|
+
* This value MUST match the `version` field in `package.json`.
|
|
765
|
+
* Update this constant whenever a new version is released via Changesets.
|
|
766
|
+
*/
|
|
767
|
+
declare const ADAPTERS_VERSION: "0.0.0";
|
|
768
|
+
|
|
769
|
+
export { ADAPTERS_VERSION, type AdapterType, type AnalyticsAdapterConfig, type AuthAdapterConfig, type DataAdapterConfig, type ErrorAdapterConfig, adapterAuthError, adapterMethodError, adapterMutationError, adapterQueryError, adapterValidationError, createAnalyticsAdapter, createAuthAdapter, createDataAdapter, createErrorAdapter, createNoopAnalyticsAdapter, createNoopAuthAdapter, createNoopDataAdapter, createNoopErrorAdapter, validateAdapterConfig };
|