@objectstack/service-datasource 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +28 -0
- package/CHANGELOG.md +94 -0
- package/LICENSE +202 -0
- package/LICENSE.apache +202 -0
- package/README.md +50 -0
- package/dist/contracts/index.cjs +1 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +178 -0
- package/dist/contracts/index.d.ts +178 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/index.cjs +995 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +414 -0
- package/dist/index.d.ts +414 -0
- package/dist/index.js +995 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/admin-routes.test.ts +106 -0
- package/src/__tests__/datasource-admin-plugin.test.ts +231 -0
- package/src/__tests__/datasource-admin-service.test.ts +288 -0
- package/src/__tests__/datasource-secret-binder.test.ts +101 -0
- package/src/__tests__/external-datasource-service.test.ts +360 -0
- package/src/admin-routes.ts +117 -0
- package/src/contracts/datasource-admin-service.ts +119 -0
- package/src/contracts/datasource-driver-factory.ts +77 -0
- package/src/contracts/index.ts +18 -0
- package/src/datasource-admin-plugin.ts +362 -0
- package/src/datasource-admin-service.ts +297 -0
- package/src/datasource-secret-binder.ts +144 -0
- package/src/default-datasource-driver-factory.ts +185 -0
- package/src/external-datasource-service.ts +456 -0
- package/src/index.ts +73 -0
- package/src/logger.ts +11 -0
- package/src/plugin.ts +119 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +19 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { IExternalDatasourceService, IntrospectedSchema, RemoteTable, GenerateDraftOpts, ObjectDraft, ImportObjectOpts, ImportObjectResult, SchemaValidationResult, SchemaValidationReport, ICryptoProvider, IHttpServer } from '@objectstack/spec/contracts';
|
|
2
|
+
import { ExternalCatalog } from '@objectstack/spec/data';
|
|
3
|
+
import { Plugin, PluginContext } from '@objectstack/core';
|
|
4
|
+
import { IDatasourceAdminService, TestConnectionResult, SecretInput, DatasourceSummary, DatasourceDraft, IDatasourceDriverFactory } from './contracts/index.js';
|
|
5
|
+
export { DatasourceConnectionSpec, DatasourceDriverHandle, DatasourceOrigin } from './contracts/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ExternalDatasourceService — implements {@link IExternalDatasourceService}
|
|
9
|
+
* (ADR-0015 §6) on top of driver introspection.
|
|
10
|
+
*
|
|
11
|
+
* The service is intentionally decoupled from the kernel: all I/O
|
|
12
|
+
* (introspection, metadata reads) is injected via
|
|
13
|
+
* {@link ExternalDatasourceServiceConfig}, so the introspection/draft/validate
|
|
14
|
+
* logic is pure and unit-testable. The kernel plugin wires the real
|
|
15
|
+
* `IDataEngine` + `IMetadataService` callbacks in.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Minimal datasource shape the service reads (subset of `Datasource`). */
|
|
19
|
+
interface DatasourceLike {
|
|
20
|
+
name: string;
|
|
21
|
+
schemaMode?: 'managed' | 'external' | 'validate-only';
|
|
22
|
+
external?: {
|
|
23
|
+
allowedSchemas?: string[];
|
|
24
|
+
validation?: {
|
|
25
|
+
onMismatch?: 'fail' | 'warn' | 'ignore';
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Minimal object shape the service reads (subset of `ServiceObject`). */
|
|
30
|
+
interface ObjectLike {
|
|
31
|
+
name: string;
|
|
32
|
+
label?: string;
|
|
33
|
+
datasource?: string;
|
|
34
|
+
external?: {
|
|
35
|
+
remoteName?: string;
|
|
36
|
+
remoteSchema?: string;
|
|
37
|
+
columnMap?: Record<string, string>;
|
|
38
|
+
ignoreColumns?: string[];
|
|
39
|
+
};
|
|
40
|
+
fields?: Record<string, {
|
|
41
|
+
type?: string;
|
|
42
|
+
required?: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
}
|
|
45
|
+
interface Logger$1 {
|
|
46
|
+
warn: (message: string, meta?: unknown) => void;
|
|
47
|
+
info?: (message: string, meta?: unknown) => void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Injected dependencies. The plugin supplies real implementations backed by
|
|
51
|
+
* the driver registry and `IMetadataService`; tests supply fakes.
|
|
52
|
+
*/
|
|
53
|
+
interface ExternalDatasourceServiceConfig {
|
|
54
|
+
/** Introspect a datasource's live schema via its driver. */
|
|
55
|
+
introspect: (datasource: string) => Promise<IntrospectedSchema>;
|
|
56
|
+
/** Resolve a datasource definition by name. */
|
|
57
|
+
getDatasource: (name: string) => Promise<DatasourceLike | undefined>;
|
|
58
|
+
/** Resolve one object definition by name. */
|
|
59
|
+
getObject: (name: string) => Promise<ObjectLike | undefined>;
|
|
60
|
+
/** List all object definitions (for `validateAll`). */
|
|
61
|
+
listObjects: () => Promise<ObjectLike[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Persist a refreshed catalog snapshot as an `external_catalog` metadata
|
|
64
|
+
* record. Optional: when absent, `refreshCatalog` still returns the snapshot
|
|
65
|
+
* but does not cache it (e.g. dev runs without a writable metadata store).
|
|
66
|
+
*/
|
|
67
|
+
persistCatalog?: (catalog: ExternalCatalog) => Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Persist an imported object definition as a live (runtime-origin) `object`
|
|
70
|
+
* metadata record. Optional: when absent, {@link ExternalDatasourceService.importObject}
|
|
71
|
+
* throws (the deployment is GitOps-only / has no writable metadata store).
|
|
72
|
+
*/
|
|
73
|
+
persistObject?: (name: string, definition: Record<string, unknown>) => Promise<void>;
|
|
74
|
+
logger?: Logger$1;
|
|
75
|
+
}
|
|
76
|
+
declare class ExternalDatasourceService implements IExternalDatasourceService {
|
|
77
|
+
private readonly config;
|
|
78
|
+
constructor(config: ExternalDatasourceServiceConfig);
|
|
79
|
+
private get logger();
|
|
80
|
+
private findTable;
|
|
81
|
+
listRemoteTables(datasource: string, opts?: {
|
|
82
|
+
schema?: string;
|
|
83
|
+
}): Promise<RemoteTable[]>;
|
|
84
|
+
generateObjectDraft(datasource: string, remoteName: string, opts?: GenerateDraftOpts): Promise<ObjectDraft>;
|
|
85
|
+
importObject(datasource: string, remoteName: string, opts?: ImportObjectOpts): Promise<ImportObjectResult>;
|
|
86
|
+
refreshCatalog(datasource: string): Promise<ExternalCatalog>;
|
|
87
|
+
validateObject(objectName: string): Promise<SchemaValidationResult>;
|
|
88
|
+
validateAll(): Promise<SchemaValidationReport>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface ExternalDatasourceServicePluginOptions {
|
|
92
|
+
/** Override the introspection function (mainly for tests). */
|
|
93
|
+
introspect?: (datasource: string) => Promise<IntrospectedSchema>;
|
|
94
|
+
logger?: Logger$1;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* ExternalDatasourceServicePlugin — registers `IExternalDatasourceService`
|
|
98
|
+
* into the kernel as the `'external-datasource'` service (ADR-0015 §6.1).
|
|
99
|
+
*
|
|
100
|
+
* It bridges the decoupled {@link ExternalDatasourceService} to the live
|
|
101
|
+
* `IDataEngine` (for driver introspection) and `IMetadataService` (for object
|
|
102
|
+
* + datasource reads).
|
|
103
|
+
*/
|
|
104
|
+
declare class ExternalDatasourceServicePlugin implements Plugin {
|
|
105
|
+
name: string;
|
|
106
|
+
version: string;
|
|
107
|
+
type: "standard";
|
|
108
|
+
dependencies: string[];
|
|
109
|
+
private service?;
|
|
110
|
+
private readonly options;
|
|
111
|
+
constructor(options?: ExternalDatasourceServicePluginOptions);
|
|
112
|
+
init(ctx: PluginContext): Promise<void>;
|
|
113
|
+
start(ctx: PluginContext): Promise<void>;
|
|
114
|
+
destroy(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Minimal logger surface used by the runtime-admin half of this package.
|
|
119
|
+
* (Structurally identical to the federation service's own `Logger`; kept
|
|
120
|
+
* separate so the admin modules carry no internal import coupling.)
|
|
121
|
+
*/
|
|
122
|
+
interface Logger {
|
|
123
|
+
warn: (message: string, meta?: unknown) => void;
|
|
124
|
+
info?: (message: string, meta?: unknown) => void;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* DatasourceAdminService — implements {@link IDatasourceAdminService}
|
|
129
|
+
* (ADR-0015 Addendum) on top of injected persistence + secret + driver probe
|
|
130
|
+
* callbacks.
|
|
131
|
+
*
|
|
132
|
+
* Like its federation sibling `ExternalDatasourceService`, this service is
|
|
133
|
+
* intentionally decoupled from the kernel: every side effect (connection probe,
|
|
134
|
+
* metadata read/write, secret write, bound-object count, hot pool (de)register)
|
|
135
|
+
* is injected via {@link DatasourceAdminServiceConfig}, so the lifecycle rules
|
|
136
|
+
* (origin gating, secret indirection, removal safety) are pure and unit-testable.
|
|
137
|
+
*
|
|
138
|
+
* Invariants enforced here, independent of the wiring:
|
|
139
|
+
* - Code-defined datasources (`origin: 'code'`) are read-only — update/remove
|
|
140
|
+
* reject them, and create refuses a name a code datasource already owns.
|
|
141
|
+
* - A runtime datasource never shadows a code one (code wins on collision).
|
|
142
|
+
* - Credentials never persist in cleartext: the cleartext {@link SecretInput}
|
|
143
|
+
* transits create/update/test only; create/update write it to the secret
|
|
144
|
+
* store and persist only the returned `credentialsRef`.
|
|
145
|
+
* - Removal is refused while objects are still bound to the datasource.
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A persisted datasource record (subset of `Datasource`). `origin` distinguishes
|
|
150
|
+
* code-defined from runtime; `external.credentialsRef` is the opaque secret
|
|
151
|
+
* handle — never a cleartext credential.
|
|
152
|
+
*/
|
|
153
|
+
interface StoredDatasource {
|
|
154
|
+
name: string;
|
|
155
|
+
label?: string;
|
|
156
|
+
driver: string;
|
|
157
|
+
schemaMode?: 'managed' | 'external' | 'validate-only';
|
|
158
|
+
config?: Record<string, unknown>;
|
|
159
|
+
external?: (Record<string, unknown> & {
|
|
160
|
+
credentialsRef?: string;
|
|
161
|
+
}) | undefined;
|
|
162
|
+
pool?: Record<string, unknown>;
|
|
163
|
+
active?: boolean;
|
|
164
|
+
origin?: 'code' | 'runtime';
|
|
165
|
+
/** Package that defines a code-origin datasource, when known. */
|
|
166
|
+
definedIn?: string;
|
|
167
|
+
}
|
|
168
|
+
/** What a connection probe needs (cleartext secret is transient, never stored). */
|
|
169
|
+
interface ProbeInput {
|
|
170
|
+
driver: string;
|
|
171
|
+
config: Record<string, unknown>;
|
|
172
|
+
/** Cleartext secret used for this probe only (e.g. password / DSN). */
|
|
173
|
+
secret?: string;
|
|
174
|
+
external?: Record<string, unknown>;
|
|
175
|
+
timeoutMs?: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Injected dependencies. The plugin supplies real implementations backed by the
|
|
179
|
+
* driver registry, `IMetadataService` (runtime store), and the secret store;
|
|
180
|
+
* tests supply fakes.
|
|
181
|
+
*/
|
|
182
|
+
interface DatasourceAdminServiceConfig {
|
|
183
|
+
/** Probe a connection live (driver connect + cheap round-trip). */
|
|
184
|
+
probe: (input: ProbeInput) => Promise<TestConnectionResult>;
|
|
185
|
+
/** Read every datasource record (code + runtime). */
|
|
186
|
+
listDatasourceRecords: () => Promise<StoredDatasource[]>;
|
|
187
|
+
/** Read one datasource record by name. */
|
|
188
|
+
getDatasourceRecord: (name: string) => Promise<StoredDatasource | undefined>;
|
|
189
|
+
/** Persist a runtime datasource record into the runtime metadata store. */
|
|
190
|
+
putDatasourceRecord: (record: StoredDatasource) => Promise<void>;
|
|
191
|
+
/** Remove a runtime datasource record from the runtime metadata store. */
|
|
192
|
+
deleteDatasourceRecord: (name: string) => Promise<void>;
|
|
193
|
+
/** Encrypt + store a secret, returning an opaque `credentialsRef`. */
|
|
194
|
+
writeSecret: (input: SecretInput, hint: {
|
|
195
|
+
name: string;
|
|
196
|
+
}) => Promise<string>;
|
|
197
|
+
/** Best-effort delete of a stored secret by ref (cleanup on remove/rewrap). */
|
|
198
|
+
removeSecret?: (credentialsRef: string) => Promise<void>;
|
|
199
|
+
/** Count objects bound to a datasource (removal blocked while > 0). */
|
|
200
|
+
countBoundObjects: (datasource: string) => Promise<number>;
|
|
201
|
+
/** Hot-(re)register a runtime datasource's connection pool after write. */
|
|
202
|
+
registerPool?: (record: StoredDatasource) => Promise<void> | void;
|
|
203
|
+
/** Tear down a runtime datasource's pool on remove. */
|
|
204
|
+
unregisterPool?: (name: string) => Promise<void> | void;
|
|
205
|
+
logger?: Logger;
|
|
206
|
+
}
|
|
207
|
+
declare class DatasourceAdminService implements IDatasourceAdminService {
|
|
208
|
+
private readonly config;
|
|
209
|
+
constructor(config: DatasourceAdminServiceConfig);
|
|
210
|
+
private get logger();
|
|
211
|
+
listDatasources(): Promise<DatasourceSummary[]>;
|
|
212
|
+
testConnection(input: DatasourceDraft, secret?: SecretInput): Promise<TestConnectionResult>;
|
|
213
|
+
createDatasource(input: DatasourceDraft, secret?: SecretInput): Promise<DatasourceSummary>;
|
|
214
|
+
updateDatasource(name: string, patch: Partial<DatasourceDraft>, secret?: SecretInput): Promise<DatasourceSummary>;
|
|
215
|
+
removeDatasource(name: string): Promise<void>;
|
|
216
|
+
private assertValidName;
|
|
217
|
+
private toRecord;
|
|
218
|
+
private toSummary;
|
|
219
|
+
private tryRegisterPool;
|
|
220
|
+
private tryUnregisterPool;
|
|
221
|
+
private tryRemoveSecret;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Host-provided secret binding. Encrypts a cleartext credential into the secret
|
|
226
|
+
* store and returns an opaque `credentialsRef`; `unbind` deletes it. Wired by
|
|
227
|
+
* the stack that owns the `ICryptoProvider` + `sys_secret` store. When absent,
|
|
228
|
+
* the plugin fails *closed*: creating/updating a datasource *with* a secret
|
|
229
|
+
* throws rather than risk persisting cleartext.
|
|
230
|
+
*/
|
|
231
|
+
interface SecretBinder {
|
|
232
|
+
bind: (input: {
|
|
233
|
+
value: string;
|
|
234
|
+
namespace?: string;
|
|
235
|
+
key?: string;
|
|
236
|
+
}, hint: {
|
|
237
|
+
name: string;
|
|
238
|
+
}) => Promise<string>;
|
|
239
|
+
unbind?: (credentialsRef: string) => Promise<void>;
|
|
240
|
+
/**
|
|
241
|
+
* Dereference a `credentialsRef` back to cleartext for opening a live
|
|
242
|
+
* connection (boot rehydration + hot pool registration). Optional: when
|
|
243
|
+
* absent, pools for secret-bearing datasources are built without the
|
|
244
|
+
* credential (fine for credential-less drivers like sqlite/memory).
|
|
245
|
+
*/
|
|
246
|
+
resolve?: (credentialsRef: string) => Promise<string | undefined>;
|
|
247
|
+
}
|
|
248
|
+
interface DatasourceAdminServicePluginOptions {
|
|
249
|
+
/** Secret binding backed by the host's crypto provider + `sys_secret`. */
|
|
250
|
+
secrets?: SecretBinder;
|
|
251
|
+
/** Override the driver factory (defaults to the `'datasource-driver-factory'` service). */
|
|
252
|
+
driverFactory?: IDatasourceDriverFactory;
|
|
253
|
+
logger?: Logger;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* DatasourceAdminServicePlugin — registers `IDatasourceAdminService` into the
|
|
257
|
+
* kernel as the `'datasource-admin'` service (ADR-0015 Addendum).
|
|
258
|
+
*
|
|
259
|
+
* Bridges the decoupled {@link DatasourceAdminService} to live infrastructure:
|
|
260
|
+
* - persistence + bound-object count via the `'metadata'` service
|
|
261
|
+
* (`register`/`unregister` write through to the runtime DB loader),
|
|
262
|
+
* - connection probe + hot pool (de)registration via the
|
|
263
|
+
* `'datasource-driver-factory'` capability and the `'data'` engine,
|
|
264
|
+
* - secret encryption via a host-provided {@link SecretBinder} (fail-closed).
|
|
265
|
+
*
|
|
266
|
+
* Every dependency degrades gracefully: a missing driver factory turns
|
|
267
|
+
* `testConnection` into a clear `{ ok: false }` and skips hot pool registration
|
|
268
|
+
* (the driver is picked up at next boot); a missing secret binder makes
|
|
269
|
+
* secret-bearing create/update fail loudly instead of leaking cleartext.
|
|
270
|
+
*/
|
|
271
|
+
declare class DatasourceAdminServicePlugin implements Plugin {
|
|
272
|
+
name: string;
|
|
273
|
+
version: string;
|
|
274
|
+
type: "standard";
|
|
275
|
+
dependencies: string[];
|
|
276
|
+
private service?;
|
|
277
|
+
private config?;
|
|
278
|
+
private readonly options;
|
|
279
|
+
constructor(options?: DatasourceAdminServicePluginOptions);
|
|
280
|
+
init(ctx: PluginContext): Promise<void>;
|
|
281
|
+
start(ctx: PluginContext): Promise<void>;
|
|
282
|
+
/**
|
|
283
|
+
* Boot-time rehydration: list persisted runtime datasources and re-register
|
|
284
|
+
* each one's connection pool (driver build → connect → registerDriver),
|
|
285
|
+
* decrypting its `sys_secret` credential on the way via the configured
|
|
286
|
+
* `registerPool` (which resolves `credentialsRef`). Code-defined datasources
|
|
287
|
+
* are owned by the host stack's own boot path and skipped here. Entirely
|
|
288
|
+
* best-effort: a missing factory/engine, an unpersisted dev store (nothing
|
|
289
|
+
* to rehydrate), or a single failing pool never blocks boot.
|
|
290
|
+
*/
|
|
291
|
+
private rehydratePools;
|
|
292
|
+
destroy(): Promise<void>;
|
|
293
|
+
private toSpec;
|
|
294
|
+
/** Probe a connection via the driver factory: build → connect → ping → close. */
|
|
295
|
+
private probe;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Default (dev/self-host) implementation of {@link IDatasourceDriverFactory}.
|
|
300
|
+
*
|
|
301
|
+
* The framework ships no universal "driver-by-id" registry — concrete drivers
|
|
302
|
+
* are constructed by the host stack (ADR-0015 Addendum §3.5). This factory is
|
|
303
|
+
* the host-side glue that lets the runtime-datasource lifecycle
|
|
304
|
+
* (`IDatasourceAdminService`) build a live driver from an *unsaved* draft so it
|
|
305
|
+
* can probe a connection before "Save" and hot-register a pool afterwards.
|
|
306
|
+
*
|
|
307
|
+
* Supported driver ids map onto the same open-core drivers the standalone
|
|
308
|
+
* stack auto-detects:
|
|
309
|
+
* - `postgres` / `pg` / `postgresql` → `@objectstack/driver-sql` (client `pg`)
|
|
310
|
+
* - `sqlite` / `sqlite3` → `@objectstack/driver-sql` (better-sqlite3)
|
|
311
|
+
* - `mongodb` / `mongo` → `@objectstack/driver-mongodb` (peer dep)
|
|
312
|
+
* - `memory` / `inmemory` → `@objectstack/driver-memory`
|
|
313
|
+
*
|
|
314
|
+
* Anything else returns `supports() === false`, so the admin service degrades
|
|
315
|
+
* gracefully (testConnection → `{ ok: false }`, create skips hot pool reg).
|
|
316
|
+
*
|
|
317
|
+
* SECURITY: the cleartext `spec.secret` is used only to open the connection and
|
|
318
|
+
* is never persisted or logged here.
|
|
319
|
+
*/
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Create the default datasource driver factory. Driver packages are imported
|
|
323
|
+
* lazily so a host that never builds (e.g.) a mongo connection doesn't pay for
|
|
324
|
+
* the mongo SDK.
|
|
325
|
+
*/
|
|
326
|
+
declare function createDefaultDatasourceDriverFactory(): IDatasourceDriverFactory;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Default datasource SecretBinder — persists a runtime datasource's cleartext
|
|
330
|
+
* credential into the `sys_secret` cipher store and returns an opaque
|
|
331
|
+
* `credentialsRef` handle (ADR-0015 Addendum, security invariant).
|
|
332
|
+
*
|
|
333
|
+
* Mirrors the SettingsService Phase-3 split: the cleartext is wrapped by an
|
|
334
|
+
* {@link ICryptoProvider} into a {@link CryptoHandle}, the ciphertext lands in a
|
|
335
|
+
* `sys_secret` row keyed by `handle.id`, and only the handle id (wrapped as
|
|
336
|
+
* `sys_secret:<id>`) is ever stored on the datasource artefact. Cleartext never
|
|
337
|
+
* touches metadata.
|
|
338
|
+
*
|
|
339
|
+
* This is the dev/self-host wiring; production hosts swap the
|
|
340
|
+
* `LocalCryptoProvider` for a KMS-backed `ICryptoProvider` and pass it here.
|
|
341
|
+
*/
|
|
342
|
+
|
|
343
|
+
/** Minimal data-engine surface used to read/write the `sys_secret` store. */
|
|
344
|
+
interface SecretStoreEngineLike {
|
|
345
|
+
insert(object: string, data: Record<string, unknown>, options?: unknown): Promise<unknown>;
|
|
346
|
+
delete(object: string, options: {
|
|
347
|
+
where: Record<string, unknown>;
|
|
348
|
+
}): Promise<unknown>;
|
|
349
|
+
/**
|
|
350
|
+
* Read `sys_secret` rows for the `resolve()` path. Optional so existing
|
|
351
|
+
* callers that only bind/unbind keep working; `resolve()` no-ops when absent.
|
|
352
|
+
* Mirrors `IDataEngine.find` — returns an array (or `{ data: [...] }`).
|
|
353
|
+
*/
|
|
354
|
+
find?(object: string, query: Record<string, unknown>): Promise<unknown>;
|
|
355
|
+
}
|
|
356
|
+
interface DatasourceSecretBinderDeps {
|
|
357
|
+
/** Data engine (ObjectQL) used to persist the `sys_secret` row. */
|
|
358
|
+
engine: SecretStoreEngineLike;
|
|
359
|
+
/** Crypto provider that wraps cleartext into a {@link CryptoHandle}. */
|
|
360
|
+
cryptoProvider: ICryptoProvider;
|
|
361
|
+
/** Settings namespace recorded on the secret row (default `'datasource'`). */
|
|
362
|
+
namespace?: string;
|
|
363
|
+
}
|
|
364
|
+
interface DatasourceSecretBinder {
|
|
365
|
+
bind(input: {
|
|
366
|
+
value: string;
|
|
367
|
+
namespace?: string;
|
|
368
|
+
key?: string;
|
|
369
|
+
}, hint: {
|
|
370
|
+
name: string;
|
|
371
|
+
}): Promise<string>;
|
|
372
|
+
unbind(credentialsRef: string): Promise<void>;
|
|
373
|
+
/**
|
|
374
|
+
* Dereference a `credentialsRef` back to its cleartext credential by reading
|
|
375
|
+
* the `sys_secret` row and decrypting it. Used at boot to rebuild a runtime
|
|
376
|
+
* datasource's live connection pool (the cleartext is never persisted, so it
|
|
377
|
+
* must be recovered from the cipher store). Returns `undefined` when the ref
|
|
378
|
+
* isn't ours, the row is gone, the engine can't read, or decryption fails
|
|
379
|
+
* (e.g. an ephemeral dev key changed across restarts) — callers degrade to
|
|
380
|
+
* skipping that pool rather than crashing boot.
|
|
381
|
+
*/
|
|
382
|
+
resolve(credentialsRef: string): Promise<string | undefined>;
|
|
383
|
+
}
|
|
384
|
+
/** Build a `credentialsRef` from a crypto handle id. */
|
|
385
|
+
declare function toCredentialsRef(handleId: string): string;
|
|
386
|
+
/** Extract the `sys_secret` handle id from a credentialsRef, if it is one. */
|
|
387
|
+
declare function parseCredentialsRef(ref: string): string | undefined;
|
|
388
|
+
/**
|
|
389
|
+
* Create the default datasource secret binder. Persists into `sys_secret` via
|
|
390
|
+
* the data engine and never returns or logs the cleartext.
|
|
391
|
+
*/
|
|
392
|
+
declare function createDatasourceSecretBinder(deps: DatasourceSecretBinderDeps): DatasourceSecretBinder;
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Datasource lifecycle REST routes (ADR-0015 Addendum §3.5).
|
|
396
|
+
*
|
|
397
|
+
* Mounted under `/api/v1/datasources` and served by the `datasource-admin`
|
|
398
|
+
* service. Every route degrades gracefully
|
|
399
|
+
* (`503 datasource_admin_unavailable`) when the service is not wired in, and
|
|
400
|
+
* lifecycle/validation failures surface as `400` with the service's message.
|
|
401
|
+
*
|
|
402
|
+
* GET /datasources → listDatasources (provenance + health)
|
|
403
|
+
* POST /datasources/test → testConnection (no persistence)
|
|
404
|
+
* POST /datasources → createDatasource (origin: 'runtime')
|
|
405
|
+
* PATCH /datasources/:name → updateDatasource (runtime only)
|
|
406
|
+
* DELETE /datasources/:name → removeDatasource (runtime only)
|
|
407
|
+
*
|
|
408
|
+
* Request bodies carry the connection draft inline with an optional cleartext
|
|
409
|
+
* `secret` field; the route splits `secret` out so it never reaches the draft
|
|
410
|
+
* the service persists.
|
|
411
|
+
*/
|
|
412
|
+
declare function registerDatasourceAdminRoutes(server: IHttpServer, ctx: PluginContext, basePath?: string): void;
|
|
413
|
+
|
|
414
|
+
export { DatasourceAdminService, type DatasourceAdminServiceConfig, DatasourceAdminServicePlugin, type DatasourceAdminServicePluginOptions, DatasourceDraft, type DatasourceLike, type DatasourceSecretBinder, type DatasourceSecretBinderDeps, DatasourceSummary, ExternalDatasourceService, type ExternalDatasourceServiceConfig, ExternalDatasourceServicePlugin, type ExternalDatasourceServicePluginOptions, IDatasourceAdminService, IDatasourceDriverFactory, type Logger$1 as Logger, type ObjectLike, type ProbeInput, type SecretBinder, SecretInput, type SecretStoreEngineLike, type StoredDatasource, TestConnectionResult, createDatasourceSecretBinder, createDefaultDatasourceDriverFactory, parseCredentialsRef, registerDatasourceAdminRoutes, toCredentialsRef };
|