@noormdev/sdk 1.0.0-alpha.2 → 1.0.0-alpha.21
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/dist/chunk-3UDETNWW.js +943 -0
- package/dist/chunk-3UDETNWW.js.map +1 -0
- package/dist/chunk-D2XW2UOP.js +42 -0
- package/dist/chunk-D2XW2UOP.js.map +1 -0
- package/dist/chunk-TBRUDUBQ.js +1099 -0
- package/dist/chunk-TBRUDUBQ.js.map +1 -0
- package/dist/chunk-UDUDHOIB.js +3136 -0
- package/dist/chunk-UDUDHOIB.js.map +1 -0
- package/dist/chunk-UOFJT5PY.js +1499 -0
- package/dist/chunk-UOFJT5PY.js.map +1 -0
- package/dist/chunk-YJBKNUTP.js +7233 -0
- package/dist/chunk-YJBKNUTP.js.map +1 -0
- package/dist/chunk-ZKYTJJIF.js +308 -0
- package/dist/chunk-ZKYTJJIF.js.map +1 -0
- package/dist/csv-T5P3IN4K.js +7 -0
- package/dist/csv-T5P3IN4K.js.map +1 -0
- package/dist/engine-27DNMF4T.js +11 -0
- package/dist/{engine-B4JH5RQJ.js.map → engine-27DNMF4T.js.map} +1 -1
- package/dist/index.d.ts +3046 -1193
- package/dist/index.js +26205 -6889
- package/dist/index.js.map +1 -1
- package/dist/json5-LNT3RGJ7.js +7 -0
- package/dist/json5-LNT3RGJ7.js.map +1 -0
- package/dist/mssql-3NNVV77C.js +121 -0
- package/dist/mssql-3NNVV77C.js.map +1 -0
- package/dist/{mysql-C2DR4TF7.js → mysql-UPMQUBLE.js} +5 -3
- package/dist/mysql-UPMQUBLE.js.map +1 -0
- package/dist/{postgres-SIDJBSIT.js → postgres-CPVTCR7W.js} +5 -3
- package/dist/postgres-CPVTCR7W.js.map +1 -0
- package/dist/{sqlite-5VZTBN5J.js → sqlite-F3ZSSDUM.js} +5 -3
- package/dist/sqlite-F3ZSSDUM.js.map +1 -0
- package/dist/sqlite-bun-LMHUMGQI.js +60 -0
- package/dist/sqlite-bun-LMHUMGQI.js.map +1 -0
- package/dist/storage-TZNQBIX3.js +8 -0
- package/dist/storage-TZNQBIX3.js.map +1 -0
- package/dist/yaml-XI7RQ2D5.js +7 -0
- package/dist/yaml-XI7RQ2D5.js.map +1 -0
- package/package.json +8 -4
- package/dist/chunk-MERTHCAJ.js +0 -299
- package/dist/chunk-MERTHCAJ.js.map +0 -1
- package/dist/engine-B4JH5RQJ.js +0 -3
- package/dist/mssql-T4M7OGEC.js +0 -46
- package/dist/mssql-T4M7OGEC.js.map +0 -1
- package/dist/mysql-C2DR4TF7.js.map +0 -1
- package/dist/postgres-SIDJBSIT.js.map +0 -1
- package/dist/sqlite-5VZTBN5J.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
-
import { Kysely } from 'kysely';
|
|
3
|
+
import { Generated, Kysely, Transaction } from 'kysely';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Supported database dialects.
|
|
@@ -45,6 +45,14 @@ export interface ConnectionConfig {
|
|
|
45
45
|
key?: string;
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Result of creating a connection.
|
|
50
|
+
*/
|
|
51
|
+
export interface ConnectionResult {
|
|
52
|
+
db: Kysely<unknown>;
|
|
53
|
+
dialect: Dialect;
|
|
54
|
+
destroy: () => Promise<void>;
|
|
55
|
+
}
|
|
48
56
|
/**
|
|
49
57
|
* Full configuration object.
|
|
50
58
|
*
|
|
@@ -63,10 +71,6 @@ export interface ConnectionConfig {
|
|
|
63
71
|
* user: 'postgres',
|
|
64
72
|
* password: 'postgres',
|
|
65
73
|
* },
|
|
66
|
-
* paths: {
|
|
67
|
-
* sql: './sql',
|
|
68
|
-
* changes: './changes',
|
|
69
|
-
* },
|
|
70
74
|
* }
|
|
71
75
|
* ```
|
|
72
76
|
*/
|
|
@@ -76,194 +80,871 @@ export interface Config {
|
|
|
76
80
|
isTest: boolean;
|
|
77
81
|
protected: boolean;
|
|
78
82
|
connection: ConnectionConfig;
|
|
79
|
-
paths: {
|
|
80
|
-
sql: string;
|
|
81
|
-
changes: string;
|
|
82
|
-
};
|
|
83
83
|
identity?: string;
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
*
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
85
|
+
export type Events<Shape> = keyof Shape;
|
|
86
|
+
declare namespace ObserverEngine {
|
|
87
|
+
interface EventCallback<Shape> {
|
|
88
|
+
(data: Shape, info?: {
|
|
89
|
+
event: string;
|
|
90
|
+
listener: Function;
|
|
91
|
+
} | undefined): void;
|
|
92
|
+
}
|
|
93
|
+
type RgxEmitData<Shape> = {
|
|
94
|
+
event: Events<Shape>;
|
|
95
|
+
data: Shape[Events<Shape>];
|
|
96
|
+
};
|
|
97
|
+
type Cleanup = () => void;
|
|
98
|
+
type Component<Ev extends Record<string, any>> = {
|
|
99
|
+
on: ObserverEngine<Ev>["on"];
|
|
100
|
+
once: ObserverEngine<Ev>["once"];
|
|
101
|
+
emit: ObserverEngine<Ev>["emit"];
|
|
102
|
+
off: ObserverEngine<Ev>["off"];
|
|
103
|
+
};
|
|
104
|
+
type Child<C, Ev extends Record<string, any>> = C & Component<Ev> & {
|
|
105
|
+
cleanup: Cleanup;
|
|
106
|
+
clear: Cleanup;
|
|
107
|
+
};
|
|
108
|
+
type Instance<Ev extends Record<string, any>> = Component<Ev> & {
|
|
109
|
+
observe: ObserverEngine<Ev>["observe"];
|
|
110
|
+
$observer: ObserverEngine<Ev>;
|
|
111
|
+
};
|
|
112
|
+
type FuncName = "on" | "once" | "off" | "emit" | "cleanup";
|
|
113
|
+
type SpyAction<Ev extends Record<string, any>> = {
|
|
114
|
+
event: keyof Ev | RegExp | "*";
|
|
115
|
+
listener?: Function | null | undefined;
|
|
116
|
+
data?: unknown | undefined;
|
|
117
|
+
fn: FuncName;
|
|
118
|
+
context: ObserverEngine<any>;
|
|
119
|
+
};
|
|
120
|
+
interface Spy<Ev extends Record<string, any>> {
|
|
121
|
+
(action: SpyAction<Ev>): void;
|
|
122
|
+
}
|
|
123
|
+
interface EmitValidator<Ev extends Record<string, any>> {
|
|
124
|
+
(event: keyof Ev, data: Ev[keyof Ev], context: ObserverEngine<Ev>): void;
|
|
125
|
+
(event: RegExp, data: unknown, context: ObserverEngine<Ev>): void;
|
|
126
|
+
(event: "*", data: unknown, context: ObserverEngine<Ev>): void;
|
|
127
|
+
}
|
|
128
|
+
type Options<Ev extends Record<string, any>> = {
|
|
129
|
+
name?: string | undefined;
|
|
130
|
+
spy?: Spy<Ev> | undefined;
|
|
131
|
+
emitValidator?: EmitValidator<Ev> | undefined;
|
|
132
|
+
signal?: AbortSignal | undefined;
|
|
133
|
+
};
|
|
134
|
+
type ListenerOptions = {
|
|
135
|
+
signal?: AbortSignal | undefined;
|
|
136
|
+
};
|
|
137
|
+
type ObserveOptions = {
|
|
138
|
+
signal?: AbortSignal | undefined;
|
|
139
|
+
};
|
|
140
|
+
type TransferOptions<Ev extends Record<string, any>> = {
|
|
141
|
+
filter?: (Events<Ev> | RegExp)[];
|
|
142
|
+
exclude?: (Events<Ev> | RegExp)[];
|
|
143
|
+
};
|
|
141
144
|
}
|
|
142
145
|
/**
|
|
143
|
-
*
|
|
146
|
+
* Generic function type for type-safe function signatures.
|
|
144
147
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
148
|
+
* Enables consistent typing across utility functions and higher-order functions
|
|
149
|
+
* where function parameters need to be strongly typed.
|
|
147
150
|
*
|
|
148
151
|
* @example
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* prod:
|
|
152
|
-
* description: Production database
|
|
153
|
-
* locked: true
|
|
154
|
-
* defaults:
|
|
155
|
-
* dialect: postgres
|
|
156
|
-
* protected: true
|
|
157
|
-
* secrets:
|
|
158
|
-
* - key: DB_PASSWORD
|
|
159
|
-
* type: password
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
export interface Stage {
|
|
163
|
-
/** Human-readable description shown in CLI */
|
|
164
|
-
description?: string;
|
|
165
|
-
/** If true, configs linked to this stage cannot be deleted */
|
|
166
|
-
locked?: boolean;
|
|
167
|
-
/** Default values when creating config from this stage */
|
|
168
|
-
defaults?: StageDefaults;
|
|
169
|
-
/** Required secrets that must be set before config is usable */
|
|
170
|
-
secrets?: StageSecret[];
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Conditions for rule matching.
|
|
174
|
-
*
|
|
175
|
-
* All conditions in a rule are AND'd together.
|
|
176
|
-
* A rule matches when ALL specified conditions are true.
|
|
152
|
+
* function memoize<A extends any[], R>(fn: Func<A, R>): Func<A, R>
|
|
153
|
+
* function debounce<A extends any[]>(fn: Func<A, void>, ms: number): Func<A, void>
|
|
177
154
|
*/
|
|
178
|
-
export
|
|
179
|
-
/** Config name (exact match) */
|
|
180
|
-
name?: string;
|
|
181
|
-
/** Protected config flag */
|
|
182
|
-
protected?: boolean;
|
|
183
|
-
/** Test database flag */
|
|
184
|
-
isTest?: boolean;
|
|
185
|
-
/** Connection type */
|
|
186
|
-
type?: "local" | "remote";
|
|
187
|
-
}
|
|
155
|
+
export type Func<A extends any[] = any[], R = any> = (...args: A) => R;
|
|
188
156
|
/**
|
|
189
|
-
*
|
|
157
|
+
* Represents a value that can be either synchronous or asynchronous.
|
|
190
158
|
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
159
|
+
* Critical for utility functions that need to handle both sync and async
|
|
160
|
+
* operations uniformly, enabling flexible API design.
|
|
193
161
|
*
|
|
194
162
|
* @example
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* - match:
|
|
198
|
-
* isTest: true
|
|
199
|
-
* include:
|
|
200
|
-
* - sql/seeds
|
|
201
|
-
* - match:
|
|
202
|
-
* protected: true
|
|
203
|
-
* exclude:
|
|
204
|
-
* - sql/dangerous
|
|
205
|
-
* ```
|
|
163
|
+
* function processData<T>(processor: () => MaybePromise<T>): Promise<T>
|
|
164
|
+
* function transform<T, U>(value: T, transformer: (val: T) => MaybePromise<U>): Promise<U>
|
|
206
165
|
*/
|
|
207
|
-
export
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
/** Conditions that must all match */
|
|
211
|
-
match: RuleMatch;
|
|
212
|
-
/** Folders to include when rule matches */
|
|
213
|
-
include?: string[];
|
|
214
|
-
/** Folders to exclude when rule matches */
|
|
215
|
-
exclude?: string[];
|
|
166
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
167
|
+
export interface EventGeneratorOptions {
|
|
168
|
+
signal?: AbortSignal | undefined;
|
|
216
169
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
170
|
+
declare class EventGenerator<S extends Record<string, any>, E extends Events<S> | RegExp = Events<S>> {
|
|
171
|
+
cleanup: ObserverEngine.Cleanup;
|
|
172
|
+
next: () => Promise<EventData<S, E>>;
|
|
173
|
+
constructor(observer: ObserverEngine<S>, event: E | RegExp, options?: EventGeneratorOptions);
|
|
174
|
+
[Symbol.asyncIterator](): AsyncGenerator<Awaited<EventData<S, E>>, undefined, unknown>;
|
|
175
|
+
get lastValue(): E extends Events<S> ? S[E] : E extends RegExp ? ObserverEngine.RgxEmitData<S> : S[Events<S>];
|
|
176
|
+
get done(): boolean;
|
|
177
|
+
emit(data?: (E extends Events<S> ? S[E] : S[Events<S>])): void;
|
|
178
|
+
}
|
|
179
|
+
declare class ObserverEngine<Shape extends Record<string, any> = Record<string, any>> {
|
|
180
|
+
constructor(options?: ObserverEngine.Options<Shape>);
|
|
181
|
+
name: string;
|
|
221
182
|
/**
|
|
222
|
-
*
|
|
223
|
-
* First listed = first executed.
|
|
183
|
+
* Returns facts about the the internal state of the observable instance.
|
|
224
184
|
*/
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
185
|
+
$facts(): {
|
|
186
|
+
listeners: (keyof Shape)[];
|
|
187
|
+
rgxListeners: string[];
|
|
188
|
+
listenerCounts: Record<string, number>;
|
|
189
|
+
hasSpy: boolean;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* The internals of the observable instance.
|
|
193
|
+
*
|
|
194
|
+
* NOTE: Do not use this to try to meddle with the
|
|
195
|
+
* internals of the observable instance. This is for
|
|
196
|
+
* debugging purposes only.
|
|
197
|
+
*/
|
|
198
|
+
$internals(): {
|
|
199
|
+
listenerMap: Map<keyof Shape, Set<Func>>;
|
|
200
|
+
rgxListenerMap: Map<string, Set<Func>>;
|
|
201
|
+
internalListener: EventTarget;
|
|
202
|
+
name: string;
|
|
203
|
+
spy: ObserverEngine.Spy<Shape> | undefined;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Returns if the observable instance has the given event
|
|
207
|
+
*/
|
|
208
|
+
$has(event: Events<Shape>): boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Returns if the observable instance has a regex event
|
|
211
|
+
*/
|
|
212
|
+
$has(event: RegExp): boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Returns if the observable instance has the given event
|
|
215
|
+
*/
|
|
216
|
+
$has(event: string): boolean;
|
|
217
|
+
/**
|
|
218
|
+
* Enables or disables debugging for the observable instance.
|
|
219
|
+
* Works in conjunction with your spy function. Provides a
|
|
220
|
+
* stack trace of events that are triggered, listened to, and
|
|
221
|
+
* cleaned up.
|
|
222
|
+
*
|
|
223
|
+
* @param on Whether to enable or disable debugging
|
|
224
|
+
*/
|
|
225
|
+
debug(on?: boolean): void;
|
|
226
|
+
/**
|
|
227
|
+
* Sets the spy function for the observable instance.
|
|
228
|
+
* @param spy The spy function to set
|
|
229
|
+
* @param force Whether to force the spy function to be set even if one is already set
|
|
230
|
+
*/
|
|
231
|
+
spy(spy: ObserverEngine.Spy<Shape>, force?: boolean): void;
|
|
232
|
+
/**
|
|
233
|
+
* Observes given component as an extension of this observable instance.
|
|
234
|
+
* @param component Component to wrap events around
|
|
235
|
+
* @param options Optional configuration including signal for cleanup
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
*
|
|
239
|
+
* const obs = new ObserverEngine();
|
|
240
|
+
*
|
|
241
|
+
* const modal = {};
|
|
242
|
+
*
|
|
243
|
+
* obs.observe(modal);
|
|
244
|
+
*
|
|
245
|
+
* modal.on('modal-open', () => {});
|
|
246
|
+
*
|
|
247
|
+
* obs.trigger('modal-open'); // opens modal
|
|
248
|
+
* modal.trigger('modal-open'); // opens modal
|
|
249
|
+
*
|
|
250
|
+
* modal.cleanup(); // clears all event listeners
|
|
251
|
+
*/
|
|
252
|
+
observe<C>(component: C, options?: ObserverEngine.ObserveOptions): ObserverEngine.Child<C, Shape>;
|
|
253
|
+
/**
|
|
254
|
+
* Returns an event generator that will listen for the specified event
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
*
|
|
258
|
+
* const obs = new ObserverEngine();
|
|
259
|
+
*
|
|
260
|
+
* const something = obs.on('something');
|
|
261
|
+
* const data = await something.next(); // waits for next event
|
|
262
|
+
* something.emit('special'); // emits data to listeners
|
|
263
|
+
*
|
|
264
|
+
* something.cleanup(); // stops listening for events
|
|
265
|
+
*/
|
|
266
|
+
on<E extends Events<Shape>>(event: E, options?: ObserverEngine.ListenerOptions): EventGenerator<Shape, E>;
|
|
267
|
+
on<E extends string>(event: E, options?: ObserverEngine.ListenerOptions): EventGenerator<Record<E, any>>;
|
|
268
|
+
/**
|
|
269
|
+
* Listens for the specified event and executes the given callback
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
*
|
|
273
|
+
* const obs = new ObserverEngine();
|
|
274
|
+
*
|
|
275
|
+
* obs.on('something', (data) => {
|
|
276
|
+
* console.log(data);
|
|
277
|
+
* });
|
|
278
|
+
*/
|
|
279
|
+
on<E extends Events<Shape>>(event: E, listener: ObserverEngine.EventCallback<Shape[E]>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
280
|
+
on<E extends string>(event: E, listener: ObserverEngine.EventCallback<Record<E, any>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
281
|
+
/**
|
|
282
|
+
* Returns an event generator that will listen for all events matching the regex
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
*
|
|
286
|
+
* const obs = new ObserverEngine();
|
|
287
|
+
*
|
|
288
|
+
* const onEvent = obs.on(/some/);
|
|
289
|
+
* const { event, data } = await onEvent.next(); // waits for next event
|
|
290
|
+
* onEvent.emit('something'); // emits data to listeners
|
|
291
|
+
*
|
|
292
|
+
* onEvent.cleanup(); // stops listening for events
|
|
293
|
+
*/
|
|
294
|
+
on(event: RegExp, options?: ObserverEngine.ListenerOptions): EventGenerator<Shape, RegExp>;
|
|
295
|
+
/**
|
|
296
|
+
* Listens for all events matching the regex and executes the given callback
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
*
|
|
300
|
+
* const obs = new ObserverEngine();
|
|
301
|
+
*
|
|
302
|
+
* obs.on(/some/, ({ event, data }) => {
|
|
303
|
+
* console.log(event, data);
|
|
304
|
+
* });
|
|
305
|
+
*/
|
|
306
|
+
on(event: RegExp, listener: ObserverEngine.EventCallback<ObserverEngine.RgxEmitData<Shape>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
307
|
+
/**
|
|
308
|
+
* Returns an event promise that resolves when
|
|
309
|
+
* the specified event is emitted
|
|
310
|
+
*/
|
|
311
|
+
once<E extends Events<Shape>>(event: E, options?: ObserverEngine.ListenerOptions): EventPromise<Shape[E]>;
|
|
312
|
+
/**
|
|
313
|
+
* Returns an event promise that resolves when
|
|
314
|
+
* the specified event is emitted. This overload
|
|
315
|
+
* is untyped and can be used to listen for any
|
|
316
|
+
* event that is emitted.
|
|
317
|
+
*/
|
|
318
|
+
once<E extends string>(event: E, options?: ObserverEngine.ListenerOptions): EventPromise<Record<E, any>>;
|
|
319
|
+
/**
|
|
320
|
+
* Executes a callback once when the specified
|
|
321
|
+
* event is emitted
|
|
322
|
+
*/
|
|
323
|
+
once<E extends Events<Shape>>(event: E, listener: ObserverEngine.EventCallback<Shape[E]>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
324
|
+
/**
|
|
325
|
+
* Executes a callback once when the specified
|
|
326
|
+
* event is emitted. This overload is untyped
|
|
327
|
+
* and can be used to listen for any event that
|
|
328
|
+
* is emitted.
|
|
329
|
+
*/
|
|
330
|
+
once<E extends string>(event: E, listener: ObserverEngine.EventCallback<Record<E, any>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
331
|
+
/**
|
|
332
|
+
* Returns an event promise that resolves when
|
|
333
|
+
* any events matching the regex are emitted
|
|
334
|
+
*/
|
|
335
|
+
once(event: RegExp, options?: ObserverEngine.ListenerOptions): EventPromise<ObserverEngine.RgxEmitData<Shape>>;
|
|
336
|
+
/**
|
|
337
|
+
* Executes a callback once when any events
|
|
338
|
+
* matching the regex are emitted
|
|
339
|
+
*/
|
|
340
|
+
once(event: RegExp, listener: ObserverEngine.EventCallback<ObserverEngine.RgxEmitData<Shape>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
341
|
+
/**
|
|
342
|
+
* Stop listening for an event
|
|
343
|
+
* @param event
|
|
344
|
+
* @param listener
|
|
345
|
+
*/
|
|
346
|
+
off(event: Events<Shape> | RegExp | string, listener?: Function): void;
|
|
347
|
+
/** Emits an event */
|
|
348
|
+
emit<E extends Events<Shape> | RegExp | string>(event: E, data?: E extends Events<Shape> ? Shape[E] : E extends string ? Record<E, any>[E] : unknown): void;
|
|
349
|
+
clear(): void;
|
|
350
|
+
queue<E extends Events<Shape> | RegExp>(event: E, process: (data: EventData<Shape, E>) => MaybePromise<any>, options: QueueOpts): EventQueue<Shape, E>;
|
|
351
|
+
/**
|
|
352
|
+
* Transfers all matching listeners from source to target, removing
|
|
353
|
+
* them from the source. Target's existing listeners are preserved.
|
|
354
|
+
*
|
|
355
|
+
* Useful when cloning an engine (e.g. FetchEngine) and carrying
|
|
356
|
+
* over observability listeners to the new instance.
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
*
|
|
360
|
+
* const old = new ObserverEngine();
|
|
361
|
+
* const next = new ObserverEngine();
|
|
362
|
+
*
|
|
363
|
+
* old.on('ready', handler);
|
|
364
|
+
*
|
|
365
|
+
* ObserverEngine.transfer(old, next);
|
|
366
|
+
* // `next` now owns the 'ready' listener; `old` has none
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
*
|
|
370
|
+
* // Transfer only specific events
|
|
371
|
+
* ObserverEngine.transfer(old, next, {
|
|
372
|
+
* filter: ['ready', /^user\./]
|
|
373
|
+
* });
|
|
374
|
+
*/
|
|
375
|
+
static transfer<Shape extends Record<string, any>>(source: ObserverEngine<Shape>, target: ObserverEngine<Shape>, options?: ObserverEngine.TransferOptions<Shape>): void;
|
|
376
|
+
/**
|
|
377
|
+
* Copies all matching listeners from source to target without
|
|
378
|
+
* removing them from the source. Target's existing listeners
|
|
379
|
+
* are preserved.
|
|
380
|
+
*
|
|
381
|
+
* Useful when forking an engine so both instances react to the
|
|
382
|
+
* same events independently.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
*
|
|
386
|
+
* const primary = new ObserverEngine();
|
|
387
|
+
* const mirror = new ObserverEngine();
|
|
388
|
+
*
|
|
389
|
+
* primary.on('update', handler);
|
|
390
|
+
*
|
|
391
|
+
* ObserverEngine.copy(primary, mirror);
|
|
392
|
+
* // Both engines now have the 'update' listener
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
*
|
|
396
|
+
* // Copy everything except internal events
|
|
397
|
+
* ObserverEngine.copy(primary, mirror, {
|
|
398
|
+
* exclude: [/^__/]
|
|
399
|
+
* });
|
|
400
|
+
*/
|
|
401
|
+
static copy<Shape extends Record<string, any>>(source: ObserverEngine<Shape>, target: ObserverEngine<Shape>, options?: ObserverEngine.TransferOptions<Shape>): void;
|
|
402
|
+
}
|
|
403
|
+
export type EventData<S, E extends Events<S> | RegExp = Events<S>> = (E extends Events<S> ? S[E] : E extends RegExp ? ObserverEngine.RgxEmitData<S> : S[Events<S>]);
|
|
404
|
+
declare class EventPromise<T> extends Promise<T> {
|
|
405
|
+
cleanup?: () => void;
|
|
406
|
+
reject?: (err: Error | string) => void;
|
|
407
|
+
resolve?: (value: T) => void;
|
|
408
|
+
}
|
|
409
|
+
declare class InternalQueueEvent<T = unknown> {
|
|
410
|
+
readonly data: T;
|
|
411
|
+
constructor(data: T);
|
|
412
|
+
}
|
|
413
|
+
declare enum QueueRejectionReason {
|
|
414
|
+
full = "Queue is full",
|
|
415
|
+
notRunning = "Queue is not running"
|
|
416
|
+
}
|
|
417
|
+
export type QueueEventData<S, E extends Events<S> | RegExp = Events<S>> = {
|
|
418
|
+
data?: EventData<S, E>;
|
|
419
|
+
_taskId?: string;
|
|
420
|
+
priority?: number;
|
|
421
|
+
reason?: QueueRejectionReason;
|
|
422
|
+
startedAt?: number;
|
|
423
|
+
rateLimited?: boolean;
|
|
424
|
+
elapsed?: number;
|
|
425
|
+
error?: Error;
|
|
426
|
+
force?: boolean;
|
|
427
|
+
pending?: number;
|
|
428
|
+
flushed?: number;
|
|
429
|
+
drained?: number;
|
|
430
|
+
count?: number;
|
|
431
|
+
};
|
|
432
|
+
export type QueueEvents<S extends Record<string, any>, E extends Events<S> | RegExp = Events<S>> = {
|
|
433
|
+
added: QueueEventData<S, E>;
|
|
434
|
+
start: void;
|
|
435
|
+
started: void;
|
|
436
|
+
stopped: void;
|
|
437
|
+
processing: QueueEventData<S, E> & {
|
|
438
|
+
startedAt: number;
|
|
439
|
+
rateLimited: boolean;
|
|
440
|
+
};
|
|
441
|
+
success: QueueEventData<S, E> & {
|
|
442
|
+
startedAt: number;
|
|
443
|
+
elapsed: number;
|
|
444
|
+
rateLimited: boolean;
|
|
445
|
+
};
|
|
446
|
+
error: QueueEventData<S, E> & {
|
|
447
|
+
error: Error;
|
|
448
|
+
rateLimited: boolean;
|
|
449
|
+
};
|
|
450
|
+
timeout: QueueEventData<S, E> & {
|
|
451
|
+
error: Error;
|
|
452
|
+
rateLimited: boolean;
|
|
453
|
+
};
|
|
454
|
+
rejected: QueueEventData<S, E> & {
|
|
455
|
+
reason: QueueRejectionReason;
|
|
456
|
+
};
|
|
457
|
+
"rate-limited": QueueEventData<S, E> & {
|
|
458
|
+
rateLimited: boolean;
|
|
459
|
+
};
|
|
460
|
+
empty: void;
|
|
461
|
+
idle: void;
|
|
462
|
+
drain: {
|
|
463
|
+
pending: number;
|
|
464
|
+
};
|
|
465
|
+
drained: {
|
|
466
|
+
pending?: number;
|
|
467
|
+
drained?: number;
|
|
468
|
+
};
|
|
469
|
+
flush: {
|
|
470
|
+
pending: number;
|
|
471
|
+
};
|
|
472
|
+
flushed: {
|
|
473
|
+
flushed: number;
|
|
474
|
+
};
|
|
475
|
+
paused: void;
|
|
476
|
+
resumed: void;
|
|
477
|
+
cleanup: void;
|
|
478
|
+
purged: {
|
|
479
|
+
count: number;
|
|
480
|
+
};
|
|
481
|
+
shutdown: {
|
|
482
|
+
force: boolean;
|
|
483
|
+
pending?: number;
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
declare enum QueueState {
|
|
487
|
+
running = "running",
|
|
488
|
+
paused = "paused",
|
|
489
|
+
stopped = "stopped",
|
|
490
|
+
draining = "draining"
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* The options for the queue
|
|
494
|
+
*/
|
|
495
|
+
export interface QueueOpts {
|
|
496
|
+
/**
|
|
497
|
+
* The name of the queue
|
|
498
|
+
*/
|
|
499
|
+
name: string;
|
|
500
|
+
/**
|
|
501
|
+
* The type of queue to use
|
|
502
|
+
*
|
|
503
|
+
* @default 'fifo'
|
|
504
|
+
*/
|
|
505
|
+
type?: "fifo" | "lifo";
|
|
506
|
+
/**
|
|
507
|
+
* The concurrency of the queue
|
|
508
|
+
*
|
|
509
|
+
* @default 1
|
|
510
|
+
*/
|
|
511
|
+
concurrency?: number;
|
|
512
|
+
/**
|
|
513
|
+
* The poll interval in milliseconds before the queue will
|
|
514
|
+
* check for new items after idle.
|
|
515
|
+
*
|
|
516
|
+
* @default 100
|
|
517
|
+
*/
|
|
518
|
+
pollIntervalMs?: number;
|
|
519
|
+
/**
|
|
520
|
+
* The jitter percentage to displace
|
|
521
|
+
* the next process time. This stops all concurrent
|
|
522
|
+
* processes from happening at the same time.
|
|
523
|
+
*
|
|
524
|
+
* @range [0, 1]
|
|
525
|
+
* @default 1
|
|
526
|
+
*/
|
|
527
|
+
jitterFactor?: number;
|
|
528
|
+
/**
|
|
529
|
+
* The interval in milliseconds before picking up the next item
|
|
530
|
+
*
|
|
531
|
+
* @note If the interval is 0, the queue will not wait between items
|
|
532
|
+
*
|
|
533
|
+
* @default 0
|
|
534
|
+
*/
|
|
535
|
+
processIntervalMs?: number;
|
|
536
|
+
/**
|
|
537
|
+
* The timeout in milliseconds before the task is considered timed out
|
|
538
|
+
*
|
|
539
|
+
* @note If the timeout is 0, the task will not be considered timed out
|
|
540
|
+
*
|
|
541
|
+
* @default 0
|
|
542
|
+
*/
|
|
543
|
+
taskTimeoutMs?: number;
|
|
544
|
+
/**
|
|
545
|
+
* The maximum size of the queue
|
|
546
|
+
*
|
|
547
|
+
* @default 999_999_999
|
|
548
|
+
*/
|
|
549
|
+
maxQueueSize?: number;
|
|
550
|
+
/**
|
|
551
|
+
* The rate limit of the queue in items per window
|
|
552
|
+
*
|
|
553
|
+
* @default 999_999_999
|
|
554
|
+
*/
|
|
555
|
+
rateLimitCapacity?: number;
|
|
556
|
+
/**
|
|
557
|
+
* The rate limit window in milliseconds
|
|
558
|
+
*
|
|
559
|
+
* @default 1000
|
|
560
|
+
*/
|
|
561
|
+
rateLimitIntervalMs?: number;
|
|
562
|
+
/**
|
|
563
|
+
* Automatically start the queue
|
|
564
|
+
*
|
|
565
|
+
* @default true
|
|
566
|
+
*/
|
|
567
|
+
autoStart?: boolean;
|
|
568
|
+
/**
|
|
569
|
+
* Whether to enable debug mode. Can be set to 'info' or 'verbose' to
|
|
570
|
+
* get more detailed output.
|
|
571
|
+
*
|
|
572
|
+
* @default false
|
|
573
|
+
*/
|
|
574
|
+
debug?: boolean | "info" | "verbose";
|
|
575
|
+
}
|
|
576
|
+
declare class EventQueue<S extends Record<string, any>, E extends Events<S> | RegExp = Events<S>> {
|
|
577
|
+
private opts;
|
|
578
|
+
constructor(opts: QueueOpts & {
|
|
579
|
+
event: E | RegExp;
|
|
580
|
+
process: (data: EventData<S, E>) => Promise<void>;
|
|
581
|
+
observer?: ObserverEngine<S>;
|
|
582
|
+
});
|
|
583
|
+
/**
|
|
584
|
+
* Start the queue if it is not already started
|
|
585
|
+
*/
|
|
586
|
+
start(): Promise<void> | undefined;
|
|
587
|
+
/**
|
|
588
|
+
* Stop the queue
|
|
589
|
+
*/
|
|
590
|
+
stop(): void;
|
|
591
|
+
/**
|
|
592
|
+
* Pause the queue
|
|
593
|
+
*/
|
|
594
|
+
pause(): Promise<void> | undefined;
|
|
595
|
+
/**
|
|
596
|
+
* Resume the queue
|
|
597
|
+
*/
|
|
598
|
+
resume(): Promise<void> | undefined;
|
|
599
|
+
/**
|
|
600
|
+
* Empty and process all items in the queue and
|
|
601
|
+
* then stop the queue. Returns the number of items
|
|
602
|
+
* processed.
|
|
603
|
+
*/
|
|
604
|
+
shutdown(force?: boolean): Promise<number>;
|
|
605
|
+
/**
|
|
606
|
+
* Executes `limit` items in the queue
|
|
607
|
+
* and then emits a `flush` event. Returns the number
|
|
608
|
+
* of items processed.
|
|
609
|
+
*/
|
|
610
|
+
flush(limit?: number): Promise<number>;
|
|
611
|
+
/**
|
|
612
|
+
* Clears the queue and emits a `purge` event. Returns
|
|
613
|
+
* the number of items purged.
|
|
614
|
+
*/
|
|
615
|
+
purge(): number;
|
|
616
|
+
/**
|
|
617
|
+
* Emit an event to the observer, which then gets
|
|
618
|
+
* picked up by the queue and processed.
|
|
619
|
+
*
|
|
620
|
+
* @param data The data to add to the queue
|
|
621
|
+
* @param priority The priority of the data
|
|
622
|
+
*
|
|
623
|
+
* @note If priority is provided, it will be used to determine the order of the data in the queue.
|
|
624
|
+
* The higher the priority, the sooner the data will be processed.
|
|
625
|
+
*
|
|
626
|
+
* @note If priority is not provided, the data will be added to the queue with a priority of 0.
|
|
627
|
+
*/
|
|
628
|
+
add(data: EventData<S, E>, priority?: number): boolean;
|
|
629
|
+
debug(on?: boolean | "info" | "verbose"): void;
|
|
630
|
+
on<K extends keyof QueueEvents<S, E>>(event: K, listener: ((payload: InternalQueueEvent<QueueEvents<S, E>[K]>) => void)): ObserverEngine.Cleanup;
|
|
631
|
+
on<K extends keyof QueueEvents<S, E>>(event: K): EventGenerator<QueueEvents<S, E>, K>;
|
|
632
|
+
once<K extends keyof QueueEvents<S, E>>(event: K): EventPromise<InternalQueueEvent<QueueEvents<S, E>[K]>>;
|
|
633
|
+
once<K extends keyof QueueEvents<S, E>>(event: K, listener: ((payload: InternalQueueEvent<QueueEvents<S, E>[K]>) => void)): ObserverEngine.Cleanup;
|
|
634
|
+
off<K extends keyof QueueEvents<S, E>>(event: K, listener?: Function): void;
|
|
635
|
+
/**
|
|
636
|
+
* The name of the queue
|
|
637
|
+
*/
|
|
638
|
+
get name(): string;
|
|
639
|
+
/**
|
|
640
|
+
* Whether the queue is waiting for the
|
|
641
|
+
* the
|
|
642
|
+
*/
|
|
643
|
+
get isWaiting(): boolean;
|
|
644
|
+
/**
|
|
645
|
+
* Whether the queue is idle
|
|
646
|
+
*/
|
|
647
|
+
get isIdle(): boolean;
|
|
648
|
+
/**
|
|
649
|
+
* Whether the queue is running
|
|
650
|
+
*/
|
|
651
|
+
get isRunning(): boolean;
|
|
652
|
+
/**
|
|
653
|
+
* Whether the queue is paused
|
|
654
|
+
*/
|
|
655
|
+
get isPaused(): boolean;
|
|
656
|
+
/**
|
|
657
|
+
* Whether the queue is stopped
|
|
658
|
+
*/
|
|
659
|
+
get isStopped(): boolean;
|
|
660
|
+
/**
|
|
661
|
+
* Whether the queue is draining
|
|
662
|
+
*/
|
|
663
|
+
get isDraining(): boolean;
|
|
664
|
+
/**
|
|
665
|
+
* The current state of the queue
|
|
666
|
+
*/
|
|
667
|
+
get state(): QueueState;
|
|
668
|
+
/**
|
|
669
|
+
* The number of items in the queue
|
|
670
|
+
*/
|
|
671
|
+
get pending(): number;
|
|
672
|
+
/**
|
|
673
|
+
* The stats of the queue
|
|
674
|
+
*/
|
|
675
|
+
get stats(): {
|
|
676
|
+
processed: number;
|
|
677
|
+
processing: number;
|
|
678
|
+
avgProcessingTime: number;
|
|
679
|
+
success: number;
|
|
680
|
+
error: number;
|
|
681
|
+
rejected: number;
|
|
682
|
+
};
|
|
683
|
+
get snapshot(): {
|
|
684
|
+
name: string;
|
|
685
|
+
state: QueueState;
|
|
686
|
+
pending: number;
|
|
687
|
+
stats: {
|
|
688
|
+
processed: number;
|
|
689
|
+
processing: number;
|
|
690
|
+
avgProcessingTime: number;
|
|
691
|
+
success: number;
|
|
692
|
+
error: number;
|
|
693
|
+
rejected: number;
|
|
694
|
+
};
|
|
695
|
+
rateLimiter: {
|
|
696
|
+
currentTokens: number;
|
|
697
|
+
capacity: number;
|
|
698
|
+
refillIntervalMs: number;
|
|
699
|
+
totalRequests: number;
|
|
700
|
+
rejectedRequests: number;
|
|
701
|
+
successfulRequests: number;
|
|
702
|
+
rejectionRate: number;
|
|
703
|
+
totalWaitTime: number;
|
|
704
|
+
waitCount: number;
|
|
705
|
+
averageWaitTime: number;
|
|
706
|
+
uptime: number;
|
|
707
|
+
createdAt: number;
|
|
708
|
+
};
|
|
709
|
+
activeRunners: number;
|
|
710
|
+
runningNodes: Set<`${number}-${number}`>;
|
|
711
|
+
isIdle: boolean;
|
|
712
|
+
isWaiting: boolean;
|
|
713
|
+
isRunning: boolean;
|
|
714
|
+
isPaused: boolean;
|
|
715
|
+
isStopped: boolean;
|
|
716
|
+
isDraining: boolean;
|
|
717
|
+
isEmpty: boolean;
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Simple types stored as native JSON values. No encoding tuple needed.
|
|
722
|
+
*/
|
|
723
|
+
export type SimpleType = "string" | "int" | "bigint" | "float" | "decimal" | "bool" | "timestamp" | "date" | "uuid";
|
|
724
|
+
/**
|
|
725
|
+
* Encoded types that always use a `[value, encoding]` tuple in .dt files.
|
|
726
|
+
*/
|
|
727
|
+
export type EncodedType = "json" | "binary" | "vector" | "array" | "text" | "custom";
|
|
728
|
+
/**
|
|
729
|
+
* All universal types recognized by the .dt format.
|
|
730
|
+
*/
|
|
731
|
+
export type UniversalType = SimpleType | EncodedType;
|
|
732
|
+
/**
|
|
733
|
+
* Column definition within a .dt schema.
|
|
734
|
+
*
|
|
735
|
+
* @example
|
|
736
|
+
* ```typescript
|
|
737
|
+
* const col: DtColumn = {
|
|
738
|
+
* name: 'embedding',
|
|
739
|
+
* type: 'vector',
|
|
740
|
+
* sourceType: 'vector(1536)',
|
|
741
|
+
* nullable: false,
|
|
742
|
+
* };
|
|
743
|
+
* ```
|
|
744
|
+
*/
|
|
745
|
+
export interface DtColumn {
|
|
746
|
+
/** Column name as it appears in the source database. */
|
|
747
|
+
name: string;
|
|
748
|
+
/** Universal type classification. */
|
|
749
|
+
type: UniversalType;
|
|
750
|
+
/** Original database-specific type (e.g., `jsonb`, `vector(1536)`). */
|
|
751
|
+
sourceType?: string;
|
|
752
|
+
/** Whether NULL values are permitted. Default: true. */
|
|
753
|
+
nullable?: boolean;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Schema validation result.
|
|
757
|
+
*/
|
|
758
|
+
export interface SchemaValidationResult {
|
|
759
|
+
/** Whether the schema is compatible with the target. */
|
|
760
|
+
valid: boolean;
|
|
761
|
+
/** Blocking errors that prevent transfer. */
|
|
762
|
+
errors: string[];
|
|
763
|
+
/** Non-blocking warnings about potential issues. */
|
|
764
|
+
warnings: string[];
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Settings Types
|
|
768
|
+
*
|
|
769
|
+
* Settings define project-wide build behavior and stage configuration.
|
|
770
|
+
* Unlike encrypted configs (credentials), settings are version controlled
|
|
771
|
+
* and shared across the team via .noorm/settings.yml
|
|
772
|
+
*/
|
|
773
|
+
/**
|
|
774
|
+
* Secret type hints for CLI input handling.
|
|
775
|
+
*
|
|
776
|
+
* - string: Plain text input
|
|
777
|
+
* - password: Masked input, no echo
|
|
778
|
+
* - api_key: Masked input, validated format
|
|
779
|
+
* - connection_string: Validated as URI
|
|
780
|
+
*/
|
|
781
|
+
export type SecretType = "string" | "password" | "api_key" | "connection_string";
|
|
782
|
+
/**
|
|
783
|
+
* Required secret definition for a stage.
|
|
784
|
+
*
|
|
785
|
+
* @example
|
|
786
|
+
* ```yaml
|
|
787
|
+
* secrets:
|
|
788
|
+
* - key: DB_PASSWORD
|
|
789
|
+
* type: password
|
|
790
|
+
* description: Database password
|
|
791
|
+
* required: true
|
|
792
|
+
* ```
|
|
793
|
+
*/
|
|
794
|
+
export interface StageSecret {
|
|
795
|
+
/** Secret key name (e.g., DB_PASSWORD) */
|
|
796
|
+
key: string;
|
|
797
|
+
/** Type hint for CLI input handling */
|
|
798
|
+
type: SecretType;
|
|
799
|
+
/** Human-readable description shown in CLI prompts */
|
|
800
|
+
description?: string;
|
|
801
|
+
/** Whether the secret is required (default: true) */
|
|
802
|
+
required?: boolean;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Stage defaults that can be overridden when creating a config.
|
|
806
|
+
*
|
|
807
|
+
* These provide initial values. Some are enforceable constraints:
|
|
808
|
+
* - protected: true - Cannot be overridden to false
|
|
809
|
+
* - isTest: true - Cannot be overridden to false
|
|
810
|
+
* - dialect - Cannot be changed after creation
|
|
811
|
+
*/
|
|
812
|
+
export interface StageDefaults {
|
|
813
|
+
dialect?: "postgres" | "mysql" | "sqlite" | "mssql";
|
|
814
|
+
host?: string;
|
|
815
|
+
port?: number;
|
|
816
|
+
database?: string;
|
|
817
|
+
user?: string;
|
|
818
|
+
password?: string;
|
|
819
|
+
ssl?: boolean;
|
|
820
|
+
isTest?: boolean;
|
|
821
|
+
protected?: boolean;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Stage definition - a preconfigured config template.
|
|
825
|
+
*
|
|
826
|
+
* Stages are team-defined config templates with defaults, constraints,
|
|
827
|
+
* and required secrets. They're managed via version control.
|
|
828
|
+
*
|
|
829
|
+
* @example
|
|
830
|
+
* ```yaml
|
|
831
|
+
* stages:
|
|
832
|
+
* prod:
|
|
833
|
+
* description: Production database
|
|
834
|
+
* locked: true
|
|
835
|
+
* defaults:
|
|
836
|
+
* dialect: postgres
|
|
837
|
+
* protected: true
|
|
838
|
+
* secrets:
|
|
839
|
+
* - key: DB_PASSWORD
|
|
840
|
+
* type: password
|
|
841
|
+
* ```
|
|
842
|
+
*/
|
|
843
|
+
export interface Stage {
|
|
844
|
+
/** Human-readable description shown in CLI */
|
|
845
|
+
description?: string;
|
|
846
|
+
/** If true, configs linked to this stage cannot be deleted */
|
|
847
|
+
locked?: boolean;
|
|
848
|
+
/** Default values when creating config from this stage */
|
|
849
|
+
defaults?: StageDefaults;
|
|
850
|
+
/** Required secrets that must be set before config is usable */
|
|
851
|
+
secrets?: StageSecret[];
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Conditions for rule matching.
|
|
855
|
+
*
|
|
856
|
+
* All conditions in a rule are AND'd together.
|
|
857
|
+
* A rule matches when ALL specified conditions are true.
|
|
858
|
+
*/
|
|
859
|
+
export interface RuleMatch {
|
|
860
|
+
/** Config name (exact match) */
|
|
861
|
+
name?: string;
|
|
862
|
+
/** Protected config flag */
|
|
863
|
+
protected?: boolean;
|
|
864
|
+
/** Test database flag */
|
|
865
|
+
isTest?: boolean;
|
|
866
|
+
/** Connection type */
|
|
867
|
+
type?: "local" | "remote";
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Stage-based rule for conditional include/exclude.
|
|
871
|
+
*
|
|
872
|
+
* Rules control which files/folders are included or excluded
|
|
873
|
+
* based on the active config's properties.
|
|
874
|
+
*
|
|
875
|
+
* @example
|
|
876
|
+
* ```yaml
|
|
877
|
+
* rules:
|
|
878
|
+
* - match:
|
|
879
|
+
* isTest: true
|
|
880
|
+
* include:
|
|
881
|
+
* - sql/seeds
|
|
882
|
+
* - match:
|
|
883
|
+
* protected: true
|
|
884
|
+
* exclude:
|
|
885
|
+
* - sql/dangerous
|
|
886
|
+
* ```
|
|
887
|
+
*/
|
|
888
|
+
export interface Rule {
|
|
889
|
+
/** User-friendly description (e.g., "test seeds", "prod config") */
|
|
890
|
+
description?: string;
|
|
891
|
+
/** Conditions that must all match */
|
|
892
|
+
match: RuleMatch;
|
|
893
|
+
/** Folders to include when rule matches */
|
|
894
|
+
include?: string[];
|
|
895
|
+
/** Folders to exclude when rule matches */
|
|
896
|
+
exclude?: string[];
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Build configuration - controls file inclusion and execution order.
|
|
900
|
+
*/
|
|
901
|
+
export interface BuildConfig {
|
|
902
|
+
/**
|
|
903
|
+
* Folders to include, executed in this order.
|
|
904
|
+
* First listed = first executed.
|
|
905
|
+
*/
|
|
906
|
+
include?: string[];
|
|
907
|
+
/** Folders to exclude from all builds */
|
|
908
|
+
exclude?: string[];
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Path configuration - override default locations.
|
|
912
|
+
*/
|
|
913
|
+
export interface PathConfig {
|
|
914
|
+
/** Path to SQL files (relative to project root) */
|
|
915
|
+
sql?: string;
|
|
916
|
+
/** Path to change files (relative to project root) */
|
|
917
|
+
changes?: string;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Strict mode configuration.
|
|
921
|
+
*
|
|
922
|
+
* When enabled, requires certain stages to exist before operations can run.
|
|
923
|
+
*/
|
|
924
|
+
export interface StrictConfig {
|
|
925
|
+
/** Enable strict mode */
|
|
926
|
+
enabled?: boolean;
|
|
927
|
+
/** Required stage names that must have configs */
|
|
928
|
+
stages?: string[];
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Logging configuration.
|
|
932
|
+
*/
|
|
933
|
+
export interface LoggingConfig {
|
|
934
|
+
/** Enable file logging */
|
|
935
|
+
enabled?: boolean;
|
|
936
|
+
/** Minimum level to capture: silent, error, warn, info, verbose */
|
|
937
|
+
level?: "silent" | "error" | "warn" | "info" | "verbose";
|
|
938
|
+
/** Log file path (relative to project root) */
|
|
939
|
+
file?: string;
|
|
940
|
+
/** Rotate log when size exceeded (e.g., '10mb') */
|
|
941
|
+
maxSize?: string;
|
|
942
|
+
/** Number of rotated files to keep */
|
|
943
|
+
maxFiles?: number;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Teardown configuration.
|
|
947
|
+
*
|
|
267
948
|
* Controls database reset and teardown behavior.
|
|
268
949
|
*
|
|
269
950
|
* @example
|
|
@@ -378,170 +1059,628 @@ export interface SettingsEvents {
|
|
|
378
1059
|
};
|
|
379
1060
|
}
|
|
380
1061
|
/**
|
|
381
|
-
*
|
|
1062
|
+
* Version tracking table.
|
|
1063
|
+
*
|
|
1064
|
+
* Tracks noorm CLI version and all internal schema versions for migrations.
|
|
1065
|
+
* See: plan/datamodel.md#__noorm_version__
|
|
1066
|
+
*/
|
|
1067
|
+
export interface NoormVersionTable {
|
|
1068
|
+
/** Primary key */
|
|
1069
|
+
id: Generated<number>;
|
|
1070
|
+
/** CLI semver (e.g., "1.2.3") */
|
|
1071
|
+
cli_version: string;
|
|
1072
|
+
/** Database tracking tables version */
|
|
1073
|
+
noorm_version: number;
|
|
1074
|
+
/** State file (state.enc) schema version */
|
|
1075
|
+
state_version: number;
|
|
1076
|
+
/** Settings file (settings.yml) schema version */
|
|
1077
|
+
settings_version: number;
|
|
1078
|
+
/** First installation timestamp */
|
|
1079
|
+
installed_at: Generated<Date>;
|
|
1080
|
+
/** Last upgrade timestamp */
|
|
1081
|
+
upgraded_at: Generated<Date>;
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Operation status values.
|
|
1085
|
+
*
|
|
1086
|
+
* - pending: Operation started but not finished
|
|
1087
|
+
* - success: Operation completed successfully
|
|
1088
|
+
* - failed: Operation failed with error
|
|
1089
|
+
* - reverted: Operation was reverted
|
|
1090
|
+
* - stale: Operation's schema objects were torn down (needs re-run)
|
|
1091
|
+
*/
|
|
1092
|
+
export type OperationStatus = "pending" | "success" | "failed" | "reverted" | "stale";
|
|
1093
|
+
/**
|
|
1094
|
+
* Change type values.
|
|
1095
|
+
*/
|
|
1096
|
+
export type ChangeType = "build" | "run" | "change";
|
|
1097
|
+
/**
|
|
1098
|
+
* Direction values.
|
|
1099
|
+
*/
|
|
1100
|
+
export type Direction = "change" | "revert";
|
|
1101
|
+
/**
|
|
1102
|
+
* Change tracking table.
|
|
1103
|
+
*
|
|
1104
|
+
* Tracks all operation batches—changes, builds, and ad-hoc runs.
|
|
1105
|
+
* See: plan/datamodel.md#__noorm_change__
|
|
1106
|
+
*/
|
|
1107
|
+
export interface NoormChangeTable {
|
|
1108
|
+
/** Primary key */
|
|
1109
|
+
id: Generated<number>;
|
|
1110
|
+
/** Operation identifier */
|
|
1111
|
+
name: string;
|
|
1112
|
+
/** 'build', 'run', or 'change' */
|
|
1113
|
+
change_type: ChangeType;
|
|
1114
|
+
/** 'change' or 'revert' */
|
|
1115
|
+
direction: Direction;
|
|
1116
|
+
/** SHA-256 of sorted file checksums */
|
|
1117
|
+
checksum: Generated<string>;
|
|
1118
|
+
/** When executed */
|
|
1119
|
+
executed_at: Generated<Date>;
|
|
1120
|
+
/** Identity string */
|
|
1121
|
+
executed_by: Generated<string>;
|
|
1122
|
+
/** Which config was used */
|
|
1123
|
+
config_name: Generated<string>;
|
|
1124
|
+
/** noorm version */
|
|
1125
|
+
cli_version: Generated<string>;
|
|
1126
|
+
/** 'pending', 'success', 'failed', 'reverted' */
|
|
1127
|
+
status: OperationStatus;
|
|
1128
|
+
/** Error details (empty = no error) */
|
|
1129
|
+
error_message: Generated<string>;
|
|
1130
|
+
/** Execution time (0 = never ran) */
|
|
1131
|
+
duration_ms: Generated<number>;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* File execution status values.
|
|
1135
|
+
*/
|
|
1136
|
+
export type ExecutionStatus = "pending" | "success" | "failed" | "skipped";
|
|
1137
|
+
/**
|
|
1138
|
+
* File type values.
|
|
1139
|
+
*/
|
|
1140
|
+
export type FileType = "sql" | "txt";
|
|
1141
|
+
/**
|
|
1142
|
+
* Executions tracking table.
|
|
1143
|
+
*
|
|
1144
|
+
* Tracks individual file executions within an operation.
|
|
1145
|
+
* See: plan/datamodel.md#__noorm_executions__
|
|
1146
|
+
*/
|
|
1147
|
+
export interface NoormExecutionsTable {
|
|
1148
|
+
/** Primary key */
|
|
1149
|
+
id: Generated<number>;
|
|
1150
|
+
/** Parent operation (FK to __noorm_change__) */
|
|
1151
|
+
change_id: number;
|
|
1152
|
+
/** File that was executed */
|
|
1153
|
+
filepath: string;
|
|
1154
|
+
/** 'sql' or 'txt' */
|
|
1155
|
+
file_type: FileType;
|
|
1156
|
+
/** SHA-256 of file contents */
|
|
1157
|
+
checksum: Generated<string>;
|
|
1158
|
+
/** noorm version */
|
|
1159
|
+
cli_version: Generated<string>;
|
|
1160
|
+
/** 'pending', 'success', 'failed', 'skipped' */
|
|
1161
|
+
status: ExecutionStatus;
|
|
1162
|
+
/** Error details (empty = no error) */
|
|
1163
|
+
error_message: Generated<string>;
|
|
1164
|
+
/** 'unchanged', 'already-run', 'change failed' */
|
|
1165
|
+
skip_reason: Generated<string>;
|
|
1166
|
+
/** Execution time (0 = never ran) */
|
|
1167
|
+
duration_ms: Generated<number>;
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Lock table.
|
|
1171
|
+
*
|
|
1172
|
+
* Prevents concurrent operations on the same database.
|
|
1173
|
+
* See: plan/datamodel.md#__noorm_lock__
|
|
1174
|
+
*/
|
|
1175
|
+
export interface NoormLockTable {
|
|
1176
|
+
/** Primary key */
|
|
1177
|
+
id: Generated<number>;
|
|
1178
|
+
/** Lock scope (config name) */
|
|
1179
|
+
config_name: string;
|
|
1180
|
+
/** Identity of holder */
|
|
1181
|
+
locked_by: string;
|
|
1182
|
+
/** When acquired */
|
|
1183
|
+
locked_at: Generated<Date>;
|
|
1184
|
+
/** Auto-expiry time */
|
|
1185
|
+
expires_at: Date;
|
|
1186
|
+
/** Lock reason (empty = none) */
|
|
1187
|
+
reason: Generated<string>;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Identities table.
|
|
1191
|
+
*
|
|
1192
|
+
* Stores user identities for team discovery.
|
|
1193
|
+
* Auto-populated on first connect when identity is set up.
|
|
1194
|
+
* See: plan/datamodel.md#__noorm_identities__
|
|
1195
|
+
*/
|
|
1196
|
+
export interface NoormIdentitiesTable {
|
|
1197
|
+
/** Primary key */
|
|
1198
|
+
id: Generated<number>;
|
|
1199
|
+
/** SHA-256(email + name + machine + os) */
|
|
1200
|
+
identity_hash: string;
|
|
1201
|
+
/** User email */
|
|
1202
|
+
email: string;
|
|
1203
|
+
/** Display name */
|
|
1204
|
+
name: string;
|
|
1205
|
+
/** Machine hostname */
|
|
1206
|
+
machine: string;
|
|
1207
|
+
/** OS platform and version */
|
|
1208
|
+
os: string;
|
|
1209
|
+
/** X25519 public key (hex) */
|
|
1210
|
+
public_key: string;
|
|
1211
|
+
/** First registration */
|
|
1212
|
+
registered_at: Generated<Date>;
|
|
1213
|
+
/** Last activity */
|
|
1214
|
+
last_seen_at: Generated<Date>;
|
|
1215
|
+
/** Vault key encrypted with user's public key (nullable for users without vault access) */
|
|
1216
|
+
encrypted_vault_key: string | null;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Vault secrets table.
|
|
1220
|
+
*
|
|
1221
|
+
* Stores encrypted secrets shared across the team.
|
|
1222
|
+
* Secrets are encrypted with a vault key that is distributed
|
|
1223
|
+
* to team members via their public keys.
|
|
1224
|
+
*/
|
|
1225
|
+
export interface NoormVaultTable {
|
|
1226
|
+
/** Primary key */
|
|
1227
|
+
id: Generated<number>;
|
|
1228
|
+
/** Secret key name (e.g., 'API_KEY', 'DB_PASSWORD') */
|
|
1229
|
+
secret_key: string;
|
|
1230
|
+
/** AES-256-GCM encrypted value (JSON: {iv, authTag, ciphertext}) */
|
|
1231
|
+
encrypted_value: string;
|
|
1232
|
+
/** Identity who set this secret */
|
|
1233
|
+
set_by: string;
|
|
1234
|
+
/** When created */
|
|
1235
|
+
created_at: Generated<Date>;
|
|
1236
|
+
/** When last updated */
|
|
1237
|
+
updated_at: Generated<Date>;
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Schema-qualified database interface for pg/mssql.
|
|
1241
|
+
*
|
|
1242
|
+
* Used with db.withSchema('noorm') — table names have no prefix.
|
|
1243
|
+
*/
|
|
1244
|
+
export interface NoormSchemaDb {
|
|
1245
|
+
version: NoormVersionTable;
|
|
1246
|
+
change: NoormChangeTable;
|
|
1247
|
+
executions: NoormExecutionsTable;
|
|
1248
|
+
lock: NoormLockTable;
|
|
1249
|
+
identities: NoormIdentitiesTable;
|
|
1250
|
+
vault: NoormVaultTable;
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Prefixed database interface for sqlite/mysql.
|
|
1254
|
+
*
|
|
1255
|
+
* Used directly — table names have __noorm_ prefix.
|
|
1256
|
+
*/
|
|
1257
|
+
export interface NoormPrefixDb {
|
|
1258
|
+
__noorm_version__: NoormVersionTable;
|
|
1259
|
+
__noorm_change__: NoormChangeTable;
|
|
1260
|
+
__noorm_executions__: NoormExecutionsTable;
|
|
1261
|
+
__noorm_lock__: NoormLockTable;
|
|
1262
|
+
__noorm_identities__: NoormIdentitiesTable;
|
|
1263
|
+
__noorm_vault__: NoormVaultTable;
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Combined database interface for all noorm tracking tables.
|
|
1267
|
+
*
|
|
1268
|
+
* Intersection of schema-qualified (pg/mssql) and prefixed (sqlite/mysql)
|
|
1269
|
+
* interfaces. Both key sets are valid — use getNoormTables(dialect) to get
|
|
1270
|
+
* the correct keys for your dialect.
|
|
1271
|
+
*
|
|
1272
|
+
* @example
|
|
1273
|
+
* ```typescript
|
|
1274
|
+
* const tables = getNoormTables(dialect);
|
|
1275
|
+
* const ndb = noormDb(db, dialect);
|
|
1276
|
+
* await ndb.selectFrom(tables.change).selectAll().execute();
|
|
1277
|
+
* ```
|
|
1278
|
+
*/
|
|
1279
|
+
export type NoormDatabase = NoormSchemaDb & NoormPrefixDb;
|
|
1280
|
+
/**
|
|
1281
|
+
* Identity types.
|
|
1282
|
+
*
|
|
1283
|
+
* Two types of identity in noorm:
|
|
1284
|
+
* 1. Audit Identity - Simple name/email for tracking "who executed this"
|
|
1285
|
+
* 2. Cryptographic Identity - Full keypair system for config sharing and team discovery
|
|
1286
|
+
*/
|
|
1287
|
+
/**
|
|
1288
|
+
* Source of audit identity resolution.
|
|
1289
|
+
*/
|
|
1290
|
+
export type IdentitySource = "state" | "config" | "env" | "git" | "system";
|
|
1291
|
+
/**
|
|
1292
|
+
* Resolved audit identity.
|
|
1293
|
+
*
|
|
1294
|
+
* Used for tracking "who" executed a change or SQL file.
|
|
1295
|
+
*
|
|
1296
|
+
* @example
|
|
1297
|
+
* ```typescript
|
|
1298
|
+
* const identity: Identity = {
|
|
1299
|
+
* name: 'John Doe',
|
|
1300
|
+
* email: 'john@example.com',
|
|
1301
|
+
* source: 'git',
|
|
1302
|
+
* }
|
|
1303
|
+
* ```
|
|
1304
|
+
*/
|
|
1305
|
+
export interface Identity {
|
|
1306
|
+
/** User's name */
|
|
1307
|
+
name: string;
|
|
1308
|
+
/** User's email (optional) */
|
|
1309
|
+
email?: string;
|
|
1310
|
+
/** How the identity was resolved */
|
|
1311
|
+
source: IdentitySource;
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* File extension type in changes.
|
|
1315
|
+
*
|
|
1316
|
+
* - 'sql' for direct SQL files (.sql, .sql.tmpl)
|
|
1317
|
+
* - 'txt' for manifest files referencing build SQL
|
|
1318
|
+
*/
|
|
1319
|
+
export type ChangeFileType = "sql" | "txt";
|
|
1320
|
+
/**
|
|
1321
|
+
* A single file within a change.
|
|
1322
|
+
*
|
|
1323
|
+
* @example
|
|
1324
|
+
* ```typescript
|
|
1325
|
+
* const file: ChangeFile = {
|
|
1326
|
+
* filename: '001_alter-users.sql',
|
|
1327
|
+
* path: '/project/changes/2024-01-15-add-users/change/001_alter-users.sql',
|
|
1328
|
+
* type: 'sql',
|
|
1329
|
+
* }
|
|
1330
|
+
* ```
|
|
1331
|
+
*/
|
|
1332
|
+
export interface ChangeFile {
|
|
1333
|
+
/** Filename (e.g., "001_alter-users.sql") */
|
|
1334
|
+
filename: string;
|
|
1335
|
+
/** Absolute path to file */
|
|
1336
|
+
path: string;
|
|
1337
|
+
/** File type */
|
|
1338
|
+
type: ChangeFileType;
|
|
1339
|
+
/** For .txt files, the resolved SQL paths (relative to schema dir) */
|
|
1340
|
+
resolvedPaths?: string[];
|
|
1341
|
+
/** Execution status after running */
|
|
1342
|
+
status?: ExecutionStatus;
|
|
1343
|
+
/** Why the file was skipped */
|
|
1344
|
+
skipReason?: string;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* A change parsed from disk.
|
|
1348
|
+
*
|
|
1349
|
+
* Contains the folder structure with change and revert files.
|
|
1350
|
+
*
|
|
1351
|
+
* @example
|
|
1352
|
+
* ```typescript
|
|
1353
|
+
* const change: Change = {
|
|
1354
|
+
* name: '2024-01-15-add-email-verification',
|
|
1355
|
+
* path: '/project/changes/2024-01-15-add-email-verification',
|
|
1356
|
+
* date: new Date('2024-01-15'),
|
|
1357
|
+
* description: 'add-email-verification',
|
|
1358
|
+
* changeFiles: [...],
|
|
1359
|
+
* revertFiles: [...],
|
|
1360
|
+
* hasChangelog: true,
|
|
1361
|
+
* }
|
|
1362
|
+
* ```
|
|
1363
|
+
*/
|
|
1364
|
+
export interface Change {
|
|
1365
|
+
/** Folder name (e.g., "2024-01-15-add-email-verification") */
|
|
1366
|
+
name: string;
|
|
1367
|
+
/** Absolute path to change folder */
|
|
1368
|
+
path: string;
|
|
1369
|
+
/** Date parsed from name (null if no date prefix) */
|
|
1370
|
+
date: Date | null;
|
|
1371
|
+
/** Human-readable description from name */
|
|
1372
|
+
description: string;
|
|
1373
|
+
/** Files in change/ folder */
|
|
1374
|
+
changeFiles: ChangeFile[];
|
|
1375
|
+
/** Files in revert/ folder */
|
|
1376
|
+
revertFiles: ChangeFile[];
|
|
1377
|
+
/** Whether changelog.md exists */
|
|
1378
|
+
hasChangelog: boolean;
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* A change with merged disk and database information.
|
|
1382
|
+
*
|
|
1383
|
+
* Used by the list command to show all changes with status.
|
|
1384
|
+
*
|
|
1385
|
+
* @example
|
|
1386
|
+
* ```typescript
|
|
1387
|
+
* const item: ChangeListItem = {
|
|
1388
|
+
* // From disk
|
|
1389
|
+
* name: '2024-01-15-add-users',
|
|
1390
|
+
* path: '/project/changes/...',
|
|
1391
|
+
* // ...other Change fields
|
|
1392
|
+
*
|
|
1393
|
+
* // From DB
|
|
1394
|
+
* status: 'success',
|
|
1395
|
+
* appliedAt: new Date(),
|
|
1396
|
+
* // ...other ChangeStatus fields
|
|
1397
|
+
*
|
|
1398
|
+
* // Computed
|
|
1399
|
+
* isNew: false,
|
|
1400
|
+
* orphaned: false,
|
|
1401
|
+
* }
|
|
1402
|
+
* ```
|
|
1403
|
+
*/
|
|
1404
|
+
export interface ChangeListItem {
|
|
1405
|
+
/** Change name (always present) */
|
|
1406
|
+
name: string;
|
|
1407
|
+
/** Absolute path to change folder */
|
|
1408
|
+
path?: string;
|
|
1409
|
+
/** Date parsed from name (null if no date prefix) */
|
|
1410
|
+
date?: Date | null;
|
|
1411
|
+
/** Human-readable description from name */
|
|
1412
|
+
description?: string;
|
|
1413
|
+
/** Files in change/ folder */
|
|
1414
|
+
changeFiles?: ChangeFile[];
|
|
1415
|
+
/** Files in revert/ folder */
|
|
1416
|
+
revertFiles?: ChangeFile[];
|
|
1417
|
+
/** Whether changelog.md exists */
|
|
1418
|
+
hasChangelog?: boolean;
|
|
1419
|
+
/** Current status */
|
|
1420
|
+
status: OperationStatus;
|
|
1421
|
+
/** When last applied (null if never) */
|
|
1422
|
+
appliedAt: Date | null;
|
|
1423
|
+
/** Who applied it */
|
|
1424
|
+
appliedBy: string | null;
|
|
1425
|
+
/** When reverted (null if not reverted) */
|
|
1426
|
+
revertedAt: Date | null;
|
|
1427
|
+
/** Error message if failed */
|
|
1428
|
+
errorMessage: string | null;
|
|
1429
|
+
/** True if exists on disk but no DB record */
|
|
1430
|
+
isNew: boolean;
|
|
1431
|
+
/** True if exists in DB but folder deleted from disk */
|
|
1432
|
+
orphaned: boolean;
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Options for executing a change.
|
|
382
1436
|
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
1437
|
+
* @example
|
|
1438
|
+
* ```typescript
|
|
1439
|
+
* const options: ChangeOptions = {
|
|
1440
|
+
* force: false,
|
|
1441
|
+
* dryRun: false,
|
|
1442
|
+
* preview: false,
|
|
1443
|
+
* }
|
|
1444
|
+
* ```
|
|
386
1445
|
*/
|
|
1446
|
+
export interface ChangeOptions {
|
|
1447
|
+
/** Re-run even if already applied. Default: false */
|
|
1448
|
+
force?: boolean;
|
|
1449
|
+
/** Render to tmp/ without executing. Default: false */
|
|
1450
|
+
dryRun?: boolean;
|
|
1451
|
+
/** Output rendered SQL without executing. Default: false */
|
|
1452
|
+
preview?: boolean;
|
|
1453
|
+
/** Write preview output to file. Default: null */
|
|
1454
|
+
output?: string | null;
|
|
1455
|
+
}
|
|
387
1456
|
/**
|
|
388
|
-
*
|
|
1457
|
+
* Options for batch operations (next, ff, rewind).
|
|
389
1458
|
*/
|
|
390
|
-
export
|
|
1459
|
+
export interface BatchChangeOptions extends ChangeOptions {
|
|
1460
|
+
/** Stop on first failure. Default: true */
|
|
1461
|
+
abortOnError?: boolean;
|
|
1462
|
+
}
|
|
391
1463
|
/**
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
* Used for tracking "who" executed a change or SQL file.
|
|
1464
|
+
* Context required to execute changes.
|
|
395
1465
|
*
|
|
396
1466
|
* @example
|
|
397
1467
|
* ```typescript
|
|
398
|
-
* const
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
1468
|
+
* const context: ChangeContext = {
|
|
1469
|
+
* db,
|
|
1470
|
+
* configName: 'dev',
|
|
1471
|
+
* identity: { name: 'Alice', email: 'alice@example.com' },
|
|
1472
|
+
* projectRoot: '/project',
|
|
1473
|
+
* changesDir: '/project/changes',
|
|
1474
|
+
* sqlDir: '/project/sql',
|
|
402
1475
|
* }
|
|
403
1476
|
* ```
|
|
404
1477
|
*/
|
|
405
|
-
export interface
|
|
406
|
-
/**
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
|
|
1478
|
+
export interface ChangeContext {
|
|
1479
|
+
/** Kysely database connection */
|
|
1480
|
+
db: Kysely<NoormDatabase>;
|
|
1481
|
+
/** Name of the active config */
|
|
1482
|
+
configName: string;
|
|
1483
|
+
/** User identity for tracking */
|
|
1484
|
+
identity: Identity;
|
|
1485
|
+
/** Project root for template resolution */
|
|
1486
|
+
projectRoot: string;
|
|
1487
|
+
/** Directory containing changes */
|
|
1488
|
+
changesDir: string;
|
|
1489
|
+
/** Schema directory for resolving .txt references */
|
|
1490
|
+
sqlDir: string;
|
|
1491
|
+
/** Config object for template context */
|
|
1492
|
+
config?: Record<string, unknown>;
|
|
1493
|
+
/** Secrets for template context */
|
|
1494
|
+
secrets?: Record<string, string>;
|
|
1495
|
+
/** Global secrets for template context */
|
|
1496
|
+
globalSecrets?: Record<string, string>;
|
|
1497
|
+
/** Database dialect for lock formatting. Default: 'postgres' */
|
|
1498
|
+
dialect?: "postgres" | "mysql" | "sqlite" | "mssql";
|
|
412
1499
|
}
|
|
413
1500
|
/**
|
|
414
|
-
*
|
|
1501
|
+
* Result of executing a single change.
|
|
415
1502
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
* -
|
|
420
|
-
*
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
*
|
|
425
|
-
|
|
426
|
-
export type Direction = "change" | "revert";
|
|
427
|
-
/**
|
|
428
|
-
* File execution status values.
|
|
429
|
-
*/
|
|
430
|
-
export type ExecutionStatus = "pending" | "success" | "failed" | "skipped";
|
|
431
|
-
/**
|
|
432
|
-
* Overview counts for all categories.
|
|
433
|
-
*/
|
|
434
|
-
export interface ExploreOverview {
|
|
435
|
-
tables: number;
|
|
436
|
-
views: number;
|
|
437
|
-
procedures: number;
|
|
438
|
-
functions: number;
|
|
439
|
-
types: number;
|
|
440
|
-
indexes: number;
|
|
441
|
-
foreignKeys: number;
|
|
442
|
-
triggers: number;
|
|
443
|
-
locks: number;
|
|
444
|
-
connections: number;
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Table summary for list display.
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```typescript
|
|
1505
|
+
* const result: ChangeResult = {
|
|
1506
|
+
* name: '2024-01-15-add-users',
|
|
1507
|
+
* direction: 'change',
|
|
1508
|
+
* status: 'success',
|
|
1509
|
+
* files: [...],
|
|
1510
|
+
* durationMs: 1234,
|
|
1511
|
+
* }
|
|
1512
|
+
* ```
|
|
448
1513
|
*/
|
|
449
|
-
export interface
|
|
1514
|
+
export interface ChangeResult {
|
|
1515
|
+
/** Change name */
|
|
450
1516
|
name: string;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
1517
|
+
/** Operation direction */
|
|
1518
|
+
direction: Direction;
|
|
1519
|
+
/** Final status */
|
|
1520
|
+
status: OperationStatus;
|
|
1521
|
+
/** Individual file results */
|
|
1522
|
+
files: ChangeFileResult[];
|
|
1523
|
+
/** Total execution time */
|
|
1524
|
+
durationMs: number;
|
|
1525
|
+
/** Error message if failed */
|
|
1526
|
+
error?: string;
|
|
1527
|
+
/** Operation ID in tracking table */
|
|
1528
|
+
operationId?: number;
|
|
454
1529
|
}
|
|
455
1530
|
/**
|
|
456
|
-
*
|
|
1531
|
+
* Result of executing a single file within a change.
|
|
457
1532
|
*/
|
|
458
|
-
export interface
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
1533
|
+
export interface ChangeFileResult {
|
|
1534
|
+
/** File path */
|
|
1535
|
+
filepath: string;
|
|
1536
|
+
/** File checksum */
|
|
1537
|
+
checksum: string;
|
|
1538
|
+
/** Execution status */
|
|
1539
|
+
status: ExecutionStatus;
|
|
1540
|
+
/** Why skipped (if skipped) */
|
|
1541
|
+
skipReason?: string;
|
|
1542
|
+
/** Execution time in milliseconds */
|
|
1543
|
+
durationMs?: number;
|
|
1544
|
+
/** Error message if failed */
|
|
1545
|
+
error?: string;
|
|
1546
|
+
/** Rendered SQL (only in preview mode) */
|
|
1547
|
+
renderedSql?: string;
|
|
466
1548
|
}
|
|
467
1549
|
/**
|
|
468
|
-
*
|
|
1550
|
+
* Result of a batch operation (next, ff, rewind).
|
|
469
1551
|
*/
|
|
470
|
-
export interface
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
1552
|
+
export interface BatchChangeResult {
|
|
1553
|
+
/** Overall status */
|
|
1554
|
+
status: "success" | "failed" | "partial";
|
|
1555
|
+
/** Results for each change */
|
|
1556
|
+
changes: ChangeResult[];
|
|
1557
|
+
/** Number of changes executed */
|
|
1558
|
+
executed: number;
|
|
1559
|
+
/** Number of changes skipped */
|
|
1560
|
+
skipped: number;
|
|
1561
|
+
/** Number of changes that failed */
|
|
1562
|
+
failed: number;
|
|
1563
|
+
/** Total execution time */
|
|
1564
|
+
durationMs: number;
|
|
481
1565
|
}
|
|
482
1566
|
/**
|
|
483
|
-
*
|
|
1567
|
+
* A single execution record from history.
|
|
484
1568
|
*/
|
|
485
|
-
export interface
|
|
1569
|
+
export interface ChangeHistoryRecord {
|
|
1570
|
+
/** Record ID */
|
|
1571
|
+
id: number;
|
|
1572
|
+
/** Change name */
|
|
486
1573
|
name: string;
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
1574
|
+
/** Operation direction */
|
|
1575
|
+
direction: Direction;
|
|
1576
|
+
/** Status */
|
|
1577
|
+
status: OperationStatus;
|
|
1578
|
+
/** When executed */
|
|
1579
|
+
executedAt: Date;
|
|
1580
|
+
/** Who executed */
|
|
1581
|
+
executedBy: string;
|
|
1582
|
+
/** Duration in milliseconds */
|
|
1583
|
+
durationMs: number;
|
|
1584
|
+
/** Error message if failed */
|
|
1585
|
+
errorMessage: string | null;
|
|
1586
|
+
/** Checksum of files */
|
|
1587
|
+
checksum: string;
|
|
492
1588
|
}
|
|
493
1589
|
/**
|
|
494
|
-
*
|
|
1590
|
+
* File execution record from history.
|
|
495
1591
|
*/
|
|
496
|
-
export interface
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
1592
|
+
export interface FileHistoryRecord {
|
|
1593
|
+
/** Record ID */
|
|
1594
|
+
id: number;
|
|
1595
|
+
/** Parent change ID */
|
|
1596
|
+
changeId: number;
|
|
1597
|
+
/** File path */
|
|
1598
|
+
filepath: string;
|
|
1599
|
+
/** File type */
|
|
1600
|
+
fileType: ChangeFileType;
|
|
1601
|
+
/** File checksum */
|
|
1602
|
+
checksum: string;
|
|
1603
|
+
/** Execution status */
|
|
1604
|
+
status: ExecutionStatus;
|
|
1605
|
+
/** Skip reason if skipped */
|
|
1606
|
+
skipReason: string | null;
|
|
1607
|
+
/** Error message if failed */
|
|
1608
|
+
errorMessage: string | null;
|
|
1609
|
+
/** Duration in milliseconds */
|
|
1610
|
+
durationMs: number;
|
|
503
1611
|
}
|
|
504
1612
|
/**
|
|
505
|
-
*
|
|
1613
|
+
* Options for creating a new change.
|
|
506
1614
|
*/
|
|
507
|
-
export interface
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
|
|
512
|
-
/** SQL statements executed (or would execute in dry-run) */
|
|
513
|
-
statements: string[];
|
|
514
|
-
/** Duration in milliseconds */
|
|
515
|
-
durationMs: number;
|
|
1615
|
+
export interface CreateChangeOptions {
|
|
1616
|
+
/** Description for the change name */
|
|
1617
|
+
description: string;
|
|
1618
|
+
/** Optional date (defaults to today) */
|
|
1619
|
+
date?: Date;
|
|
516
1620
|
}
|
|
517
1621
|
/**
|
|
518
|
-
*
|
|
1622
|
+
* Options for adding a file to a change.
|
|
519
1623
|
*/
|
|
520
|
-
export interface
|
|
521
|
-
/**
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
1624
|
+
export interface AddFileOptions {
|
|
1625
|
+
/** Descriptive name for the file */
|
|
1626
|
+
name: string;
|
|
1627
|
+
/** File type */
|
|
1628
|
+
type: ChangeFileType;
|
|
1629
|
+
/** For 'txt' type, the paths to include */
|
|
1630
|
+
paths?: string[];
|
|
1631
|
+
/** Initial content (optional) */
|
|
1632
|
+
content?: string;
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Error when change structure is invalid.
|
|
1636
|
+
*/
|
|
1637
|
+
export declare class ChangeValidationError extends Error {
|
|
1638
|
+
readonly changeName: string;
|
|
1639
|
+
readonly issue: string;
|
|
1640
|
+
readonly name: "ChangeValidationError";
|
|
1641
|
+
constructor(changeName: string, issue: string);
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Error when change is not found.
|
|
1645
|
+
*/
|
|
1646
|
+
export declare class ChangeNotFoundError extends Error {
|
|
1647
|
+
readonly changeName: string;
|
|
1648
|
+
readonly name: "ChangeNotFoundError";
|
|
1649
|
+
constructor(changeName: string);
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Error when change is already applied.
|
|
1653
|
+
*/
|
|
1654
|
+
export declare class ChangeAlreadyAppliedError extends Error {
|
|
1655
|
+
readonly changeName: string;
|
|
1656
|
+
readonly appliedAt: Date;
|
|
1657
|
+
readonly name: "ChangeAlreadyAppliedError";
|
|
1658
|
+
constructor(changeName: string, appliedAt: Date);
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Error when trying to revert an unapplied change.
|
|
1662
|
+
*/
|
|
1663
|
+
export declare class ChangeNotAppliedError extends Error {
|
|
1664
|
+
readonly changeName: string;
|
|
1665
|
+
readonly name: "ChangeNotAppliedError";
|
|
1666
|
+
constructor(changeName: string);
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Error when change is orphaned (in DB but not on disk).
|
|
1670
|
+
*/
|
|
1671
|
+
export declare class ChangeOrphanedError extends Error {
|
|
1672
|
+
readonly changeName: string;
|
|
1673
|
+
readonly name: "ChangeOrphanedError";
|
|
1674
|
+
constructor(changeName: string);
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* Error when .txt manifest has invalid references.
|
|
1678
|
+
*/
|
|
1679
|
+
export declare class ManifestReferenceError extends Error {
|
|
1680
|
+
readonly manifestPath: string;
|
|
1681
|
+
readonly missingPath: string;
|
|
1682
|
+
readonly name: "ManifestReferenceError";
|
|
1683
|
+
constructor(manifestPath: string, missingPath: string);
|
|
545
1684
|
}
|
|
546
1685
|
/**
|
|
547
1686
|
* Options for running SQL files.
|
|
@@ -635,1041 +1774,1324 @@ export interface BatchResult {
|
|
|
635
1774
|
durationMs: number;
|
|
636
1775
|
/** Change ID in tracking table */
|
|
637
1776
|
changeId?: number;
|
|
1777
|
+
/** Error message when batch fails before file execution (e.g. tracking setup failure) */
|
|
1778
|
+
error?: string;
|
|
1779
|
+
}
|
|
1780
|
+
declare class ChangeManager {
|
|
1781
|
+
#private;
|
|
1782
|
+
constructor(context: ChangeContext);
|
|
1783
|
+
/**
|
|
1784
|
+
* List all changes with status.
|
|
1785
|
+
*
|
|
1786
|
+
* Merges changes from disk with status from database.
|
|
1787
|
+
* Includes orphaned changes (in DB but not on disk).
|
|
1788
|
+
*
|
|
1789
|
+
* @returns Array of changes with merged status
|
|
1790
|
+
*/
|
|
1791
|
+
list(): Promise<ChangeListItem[]>;
|
|
1792
|
+
/**
|
|
1793
|
+
* Run a specific change by name.
|
|
1794
|
+
*
|
|
1795
|
+
* @param name - Change name
|
|
1796
|
+
* @param options - Execution options
|
|
1797
|
+
* @returns Execution result
|
|
1798
|
+
*/
|
|
1799
|
+
run(name: string, options?: ChangeOptions): Promise<ChangeResult>;
|
|
1800
|
+
/**
|
|
1801
|
+
* Run a change object directly.
|
|
1802
|
+
*/
|
|
1803
|
+
runChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
|
|
1804
|
+
/**
|
|
1805
|
+
* Revert a specific change by name.
|
|
1806
|
+
*
|
|
1807
|
+
* @param name - Change name
|
|
1808
|
+
* @param options - Execution options
|
|
1809
|
+
* @returns Execution result
|
|
1810
|
+
*/
|
|
1811
|
+
revert(name: string, options?: ChangeOptions): Promise<ChangeResult>;
|
|
1812
|
+
/**
|
|
1813
|
+
* Revert a change object directly.
|
|
1814
|
+
*/
|
|
1815
|
+
revertChange(change: Change, options?: ChangeOptions): Promise<ChangeResult>;
|
|
1816
|
+
/**
|
|
1817
|
+
* Run next N pending changes.
|
|
1818
|
+
*
|
|
1819
|
+
* @param count - Number of changes to run (default: 1)
|
|
1820
|
+
* @param options - Execution options
|
|
1821
|
+
* @returns Batch result
|
|
1822
|
+
*/
|
|
1823
|
+
next(count?: number, options?: BatchChangeOptions): Promise<BatchChangeResult>;
|
|
1824
|
+
/**
|
|
1825
|
+
* Fast-forward: run all pending changes.
|
|
1826
|
+
*
|
|
1827
|
+
* @param options - Execution options
|
|
1828
|
+
* @returns Batch result
|
|
1829
|
+
*/
|
|
1830
|
+
ff(options?: BatchChangeOptions): Promise<BatchChangeResult>;
|
|
1831
|
+
/**
|
|
1832
|
+
* Rewind: revert changes in reverse order.
|
|
1833
|
+
*
|
|
1834
|
+
* @param target - Number of changes to revert, or name to revert to
|
|
1835
|
+
* @param options - Execution options
|
|
1836
|
+
* @returns Batch result
|
|
1837
|
+
*/
|
|
1838
|
+
rewind(target: number | string, options?: BatchChangeOptions): Promise<BatchChangeResult>;
|
|
1839
|
+
/**
|
|
1840
|
+
* Get execution history.
|
|
1841
|
+
*
|
|
1842
|
+
* @param name - Optional change name (all if not provided)
|
|
1843
|
+
* @param limit - Max records to return
|
|
1844
|
+
* @returns Array of history records
|
|
1845
|
+
*/
|
|
1846
|
+
getHistory(name?: string, limit?: number): Promise<ChangeHistoryRecord[]>;
|
|
1847
|
+
/**
|
|
1848
|
+
* Get file execution history for an operation.
|
|
1849
|
+
*/
|
|
1850
|
+
getFileHistory(operationId: number): Promise<FileHistoryRecord[]>;
|
|
1851
|
+
/**
|
|
1852
|
+
* Remove a change from disk, database, or both.
|
|
1853
|
+
*
|
|
1854
|
+
* @param name - Change name
|
|
1855
|
+
* @param options - What to remove
|
|
1856
|
+
*/
|
|
1857
|
+
remove(name: string, options: {
|
|
1858
|
+
disk?: boolean;
|
|
1859
|
+
db?: boolean;
|
|
1860
|
+
}): Promise<void>;
|
|
1861
|
+
/**
|
|
1862
|
+
* Get a specific change by name.
|
|
1863
|
+
*/
|
|
1864
|
+
get(name: string): Promise<ChangeListItem | null>;
|
|
1865
|
+
/**
|
|
1866
|
+
* Load a change from disk.
|
|
1867
|
+
*/
|
|
1868
|
+
load(name: string): Promise<Change>;
|
|
638
1869
|
}
|
|
639
1870
|
/**
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
* - 'sql' for direct SQL files (.sql, .sql.tmpl)
|
|
643
|
-
* - 'txt' for manifest files referencing build SQL
|
|
644
|
-
*/
|
|
645
|
-
export type ChangeFileType = "sql" | "txt";
|
|
646
|
-
/**
|
|
647
|
-
* A single file within a change.
|
|
1871
|
+
* SDK Types.
|
|
648
1872
|
*
|
|
649
|
-
*
|
|
650
|
-
* ```typescript
|
|
651
|
-
* const file: ChangeFile = {
|
|
652
|
-
* filename: '001_alter-users.sql',
|
|
653
|
-
* path: '/project/changes/2024-01-15-add-users/change/001_alter-users.sql',
|
|
654
|
-
* type: 'sql',
|
|
655
|
-
* }
|
|
656
|
-
* ```
|
|
1873
|
+
* All interfaces and types for the noorm programmatic SDK.
|
|
657
1874
|
*/
|
|
658
|
-
export interface ChangeFile {
|
|
659
|
-
/** Filename (e.g., "001_alter-users.sql") */
|
|
660
|
-
filename: string;
|
|
661
|
-
/** Absolute path to file */
|
|
662
|
-
path: string;
|
|
663
|
-
/** File type */
|
|
664
|
-
type: ChangeFileType;
|
|
665
|
-
/** For .txt files, the resolved SQL paths (relative to schema dir) */
|
|
666
|
-
resolvedPaths?: string[];
|
|
667
|
-
/** Execution status after running */
|
|
668
|
-
status?: ExecutionStatus;
|
|
669
|
-
/** Why the file was skipped */
|
|
670
|
-
skipReason?: string;
|
|
671
|
-
}
|
|
672
1875
|
/**
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
* Used by the list command to show all changes with status.
|
|
1876
|
+
* Options for creating an SDK context.
|
|
676
1877
|
*
|
|
677
1878
|
* @example
|
|
678
1879
|
* ```typescript
|
|
679
|
-
*
|
|
680
|
-
*
|
|
681
|
-
* name: '2024-01-15-add-users',
|
|
682
|
-
* path: '/project/changes/...',
|
|
683
|
-
* // ...other Change fields
|
|
1880
|
+
* // Basic usage with stored config
|
|
1881
|
+
* const ctx = await createContext({ config: 'dev' })
|
|
684
1882
|
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
*
|
|
1883
|
+
* // Require test database for safety
|
|
1884
|
+
* const ctx = await createContext({
|
|
1885
|
+
* config: 'test',
|
|
1886
|
+
* requireTest: true,
|
|
1887
|
+
* })
|
|
689
1888
|
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
*/
|
|
696
|
-
export interface ChangeListItem {
|
|
697
|
-
/** Change name (always present) */
|
|
698
|
-
name: string;
|
|
699
|
-
/** Absolute path to change folder */
|
|
700
|
-
path?: string;
|
|
701
|
-
/** Date parsed from name (null if no date prefix) */
|
|
702
|
-
date?: Date | null;
|
|
703
|
-
/** Human-readable description from name */
|
|
704
|
-
description?: string;
|
|
705
|
-
/** Files in change/ folder */
|
|
706
|
-
changeFiles?: ChangeFile[];
|
|
707
|
-
/** Files in revert/ folder */
|
|
708
|
-
revertFiles?: ChangeFile[];
|
|
709
|
-
/** Whether changelog.md exists */
|
|
710
|
-
hasChangelog?: boolean;
|
|
711
|
-
/** Current status */
|
|
712
|
-
status: OperationStatus;
|
|
713
|
-
/** When last applied (null if never) */
|
|
714
|
-
appliedAt: Date | null;
|
|
715
|
-
/** Who applied it */
|
|
716
|
-
appliedBy: string | null;
|
|
717
|
-
/** When reverted (null if not reverted) */
|
|
718
|
-
revertedAt: Date | null;
|
|
719
|
-
/** Error message if failed */
|
|
720
|
-
errorMessage: string | null;
|
|
721
|
-
/** True if exists on disk but no DB record */
|
|
722
|
-
isNew: boolean;
|
|
723
|
-
/** True if exists in DB but folder deleted from disk */
|
|
724
|
-
orphaned: boolean;
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Options for executing a change.
|
|
1889
|
+
* // Allow destructive ops on protected config
|
|
1890
|
+
* const ctx = await createContext({
|
|
1891
|
+
* config: 'staging',
|
|
1892
|
+
* allowProtected: true,
|
|
1893
|
+
* })
|
|
728
1894
|
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
* const
|
|
732
|
-
* force: false,
|
|
733
|
-
* dryRun: false,
|
|
734
|
-
* preview: false,
|
|
735
|
-
* }
|
|
736
|
-
* ```
|
|
737
|
-
*/
|
|
738
|
-
export interface ChangeOptions {
|
|
739
|
-
/** Re-run even if already applied. Default: false */
|
|
740
|
-
force?: boolean;
|
|
741
|
-
/** Render to tmp/ without executing. Default: false */
|
|
742
|
-
dryRun?: boolean;
|
|
743
|
-
/** Output rendered SQL without executing. Default: false */
|
|
744
|
-
preview?: boolean;
|
|
745
|
-
/** Write preview output to file. Default: null */
|
|
746
|
-
output?: string | null;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Result of executing a single change.
|
|
1895
|
+
* // Env-only mode (CI/CD) - no stored config needed
|
|
1896
|
+
* // Requires NOORM_CONNECTION_DIALECT and NOORM_CONNECTION_DATABASE
|
|
1897
|
+
* const ctx = await createContext()
|
|
750
1898
|
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
* const
|
|
754
|
-
* name: '2024-01-15-add-users',
|
|
755
|
-
* direction: 'change',
|
|
756
|
-
* status: 'success',
|
|
757
|
-
* files: [...],
|
|
758
|
-
* durationMs: 1234,
|
|
759
|
-
* }
|
|
1899
|
+
* // Override stored config via NOORM_* env vars
|
|
1900
|
+
* // NOORM_CONNECTION_HOST=override.host
|
|
1901
|
+
* const ctx = await createContext({ config: 'prod' })
|
|
760
1902
|
* ```
|
|
761
1903
|
*/
|
|
762
|
-
export interface
|
|
763
|
-
/**
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
|
|
780
|
-
*/
|
|
781
|
-
export interface ChangeFileResult {
|
|
782
|
-
/** File path */
|
|
783
|
-
filepath: string;
|
|
784
|
-
/** File checksum */
|
|
785
|
-
checksum: string;
|
|
786
|
-
/** Execution status */
|
|
787
|
-
status: ExecutionStatus;
|
|
788
|
-
/** Why skipped (if skipped) */
|
|
789
|
-
skipReason?: string;
|
|
790
|
-
/** Execution time in milliseconds */
|
|
791
|
-
durationMs?: number;
|
|
792
|
-
/** Error message if failed */
|
|
793
|
-
error?: string;
|
|
794
|
-
/** Rendered SQL (only in preview mode) */
|
|
795
|
-
renderedSql?: string;
|
|
796
|
-
}
|
|
797
|
-
/**
|
|
798
|
-
* Result of a batch operation (next, ff, rewind).
|
|
799
|
-
*/
|
|
800
|
-
export interface BatchChangeResult {
|
|
801
|
-
/** Overall status */
|
|
802
|
-
status: "success" | "failed" | "partial";
|
|
803
|
-
/** Results for each change */
|
|
804
|
-
changes: ChangeResult[];
|
|
805
|
-
/** Number of changes executed */
|
|
806
|
-
executed: number;
|
|
807
|
-
/** Number of changes skipped */
|
|
808
|
-
skipped: number;
|
|
809
|
-
/** Number of changes that failed */
|
|
810
|
-
failed: number;
|
|
811
|
-
/** Total execution time */
|
|
812
|
-
durationMs: number;
|
|
1904
|
+
export interface CreateContextOptions {
|
|
1905
|
+
/**
|
|
1906
|
+
* Config name from state.
|
|
1907
|
+
*
|
|
1908
|
+
* If omitted:
|
|
1909
|
+
* - Uses `NOORM_CONFIG` env var if set
|
|
1910
|
+
* - Falls back to env-only mode if `NOORM_CONNECTION_DIALECT`
|
|
1911
|
+
* and `NOORM_CONNECTION_DATABASE` are set
|
|
1912
|
+
*/
|
|
1913
|
+
config?: string;
|
|
1914
|
+
/** Project root directory. Defaults to process.cwd() */
|
|
1915
|
+
projectRoot?: string;
|
|
1916
|
+
/** Refuse if config.isTest !== true. Default: false */
|
|
1917
|
+
requireTest?: boolean;
|
|
1918
|
+
/** Allow destructive ops on protected configs. Default: false */
|
|
1919
|
+
allowProtected?: boolean;
|
|
1920
|
+
/** Stage name for stage defaults (from settings.yml) */
|
|
1921
|
+
stage?: string;
|
|
813
1922
|
}
|
|
814
1923
|
/**
|
|
815
|
-
*
|
|
1924
|
+
* Options for build operations.
|
|
816
1925
|
*/
|
|
817
|
-
export interface
|
|
818
|
-
/**
|
|
819
|
-
|
|
820
|
-
/** Change name */
|
|
821
|
-
name: string;
|
|
822
|
-
/** Operation direction */
|
|
823
|
-
direction: Direction;
|
|
824
|
-
/** Status */
|
|
825
|
-
status: OperationStatus;
|
|
826
|
-
/** When executed */
|
|
827
|
-
executedAt: Date;
|
|
828
|
-
/** Who executed */
|
|
829
|
-
executedBy: string;
|
|
830
|
-
/** Duration in milliseconds */
|
|
831
|
-
durationMs: number;
|
|
832
|
-
/** Error message if failed */
|
|
833
|
-
errorMessage: string | null;
|
|
834
|
-
/** Checksum of files */
|
|
835
|
-
checksum: string;
|
|
1926
|
+
export interface BuildOptions {
|
|
1927
|
+
/** Skip checksum checks, rebuild everything. Default: false */
|
|
1928
|
+
force?: boolean;
|
|
836
1929
|
}
|
|
837
1930
|
/**
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
* Defines the shape of locks and options for acquiring them.
|
|
841
|
-
* Used to prevent concurrent operations on the same database.
|
|
1931
|
+
* Options for exporting a table to a .dt file.
|
|
842
1932
|
*
|
|
843
|
-
*
|
|
844
|
-
* Locks ensure only one process modifies the schema at a time.
|
|
845
|
-
*/
|
|
846
|
-
/**
|
|
847
|
-
* Lock state returned after acquisition.
|
|
1933
|
+
* Connection details (db, dialect) come from the context automatically.
|
|
848
1934
|
*
|
|
849
1935
|
* @example
|
|
850
1936
|
* ```typescript
|
|
851
|
-
* const
|
|
852
|
-
*
|
|
853
|
-
*
|
|
1937
|
+
* const [result, err] = await ctx.exportTable('users', './exports/users.dtz', {
|
|
1938
|
+
* passphrase: 'secret',
|
|
1939
|
+
* batchSize: 5000,
|
|
1940
|
+
* });
|
|
854
1941
|
* ```
|
|
855
1942
|
*/
|
|
856
|
-
interface
|
|
857
|
-
/**
|
|
858
|
-
|
|
859
|
-
/**
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
|
|
863
|
-
/** Optional reason for acquiring */
|
|
864
|
-
reason?: string;
|
|
1943
|
+
export interface ExportOptions {
|
|
1944
|
+
/** Passphrase for .dtzx encryption. */
|
|
1945
|
+
passphrase?: string;
|
|
1946
|
+
/** Schema/namespace (e.g., 'public' for PostgreSQL). */
|
|
1947
|
+
schema?: string;
|
|
1948
|
+
/** Rows per batch. Default: 1000. */
|
|
1949
|
+
batchSize?: number;
|
|
865
1950
|
}
|
|
866
1951
|
/**
|
|
867
|
-
* Options for
|
|
1952
|
+
* Options for importing a .dt file into the database.
|
|
1953
|
+
*
|
|
1954
|
+
* Connection details (db, dialect) come from the context automatically.
|
|
868
1955
|
*
|
|
869
1956
|
* @example
|
|
870
1957
|
* ```typescript
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
* waitTimeout: 30_000, // Max wait time
|
|
876
|
-
* pollInterval: 500, // Check every 500ms
|
|
877
|
-
* reason: 'Running migrations',
|
|
878
|
-
* }
|
|
1958
|
+
* const [result, err] = await ctx.importFile('./exports/users.dtz', {
|
|
1959
|
+
* onConflict: 'skip',
|
|
1960
|
+
* truncate: true,
|
|
1961
|
+
* });
|
|
879
1962
|
* ```
|
|
880
1963
|
*/
|
|
881
|
-
interface
|
|
1964
|
+
export interface ImportOptions {
|
|
1965
|
+
/** Passphrase for .dtzx decryption. */
|
|
1966
|
+
passphrase?: string;
|
|
1967
|
+
/** Rows per batch. Default: 1000. */
|
|
1968
|
+
batchSize?: number;
|
|
1969
|
+
/** Conflict strategy. Default: 'fail'. */
|
|
1970
|
+
onConflict?: "fail" | "skip" | "update" | "replace";
|
|
1971
|
+
/** Truncate target table before import. Default: false. */
|
|
1972
|
+
truncate?: boolean;
|
|
1973
|
+
}
|
|
1974
|
+
export interface ContextState {
|
|
1975
|
+
connection: ConnectionResult | null;
|
|
1976
|
+
config: Config;
|
|
1977
|
+
settings: Settings;
|
|
1978
|
+
identity: Identity;
|
|
1979
|
+
options: CreateContextOptions;
|
|
1980
|
+
projectRoot: string;
|
|
1981
|
+
changeManager: ChangeManager | null;
|
|
1982
|
+
}
|
|
1983
|
+
export declare class ChangesNamespace {
|
|
1984
|
+
#private;
|
|
1985
|
+
constructor(state: ContextState);
|
|
882
1986
|
/**
|
|
883
|
-
*
|
|
1987
|
+
* Create a new change directory with change/ and revert/ folders.
|
|
884
1988
|
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
1989
|
+
* @example
|
|
1990
|
+
* ```typescript
|
|
1991
|
+
* const change = await ctx.noorm.changes.create({ description: 'add-user-roles' })
|
|
1992
|
+
* ```
|
|
887
1993
|
*/
|
|
888
|
-
|
|
1994
|
+
create(options: CreateChangeOptions): Promise<Change>;
|
|
889
1995
|
/**
|
|
890
|
-
*
|
|
1996
|
+
* Add a file to a change.
|
|
891
1997
|
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
1998
|
+
* @example
|
|
1999
|
+
* ```typescript
|
|
2000
|
+
* const updated = await ctx.noorm.changes.addFile(change, 'change', {
|
|
2001
|
+
* name: 'create-table',
|
|
2002
|
+
* type: 'sql',
|
|
2003
|
+
* })
|
|
2004
|
+
* ```
|
|
894
2005
|
*/
|
|
895
|
-
|
|
2006
|
+
addFile(change: Change, folder: "change" | "revert", options: AddFileOptions): Promise<Change>;
|
|
896
2007
|
/**
|
|
897
|
-
*
|
|
2008
|
+
* Remove a file from a change.
|
|
898
2009
|
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
2010
|
+
* @example
|
|
2011
|
+
* ```typescript
|
|
2012
|
+
* await ctx.noorm.changes.removeFile(change, 'change', '001_create-table.sql')
|
|
2013
|
+
* ```
|
|
901
2014
|
*/
|
|
902
|
-
|
|
2015
|
+
removeFile(change: Change, folder: "change" | "revert", filename: string): Promise<Change>;
|
|
903
2016
|
/**
|
|
904
|
-
*
|
|
2017
|
+
* Rename a file in a change.
|
|
905
2018
|
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
2019
|
+
* @example
|
|
2020
|
+
* ```typescript
|
|
2021
|
+
* await ctx.noorm.changes.renameFile(change, 'change', '001_old.sql', 'new-name')
|
|
2022
|
+
* ```
|
|
908
2023
|
*/
|
|
909
|
-
|
|
2024
|
+
renameFile(change: Change, folder: "change" | "revert", oldFilename: string, newDescription: string): Promise<Change>;
|
|
910
2025
|
/**
|
|
911
|
-
*
|
|
2026
|
+
* Reorder files in a change folder.
|
|
912
2027
|
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
2028
|
+
* @example
|
|
2029
|
+
* ```typescript
|
|
2030
|
+
* await ctx.noorm.changes.reorderFiles(change, 'change', ['002_b.sql', '001_a.sql'])
|
|
2031
|
+
* ```
|
|
915
2032
|
*/
|
|
916
|
-
|
|
2033
|
+
reorderFiles(change: Change, folder: "change" | "revert", newOrder: string[]): Promise<Change>;
|
|
917
2034
|
/**
|
|
918
|
-
*
|
|
2035
|
+
* Delete a change directory from disk.
|
|
919
2036
|
*
|
|
920
|
-
*
|
|
2037
|
+
* @example
|
|
2038
|
+
* ```typescript
|
|
2039
|
+
* await ctx.noorm.changes.delete(change)
|
|
2040
|
+
* ```
|
|
921
2041
|
*/
|
|
922
|
-
|
|
2042
|
+
delete(change: Change): Promise<void>;
|
|
2043
|
+
/**
|
|
2044
|
+
* Discover all changes on disk.
|
|
2045
|
+
*
|
|
2046
|
+
* @example
|
|
2047
|
+
* ```typescript
|
|
2048
|
+
* const changes = await ctx.noorm.changes.discover()
|
|
2049
|
+
* ```
|
|
2050
|
+
*/
|
|
2051
|
+
discover(): Promise<Change[]>;
|
|
2052
|
+
/**
|
|
2053
|
+
* Parse a single change from disk by name.
|
|
2054
|
+
*
|
|
2055
|
+
* @example
|
|
2056
|
+
* ```typescript
|
|
2057
|
+
* const change = await ctx.noorm.changes.parse('2024-01-15-add-users')
|
|
2058
|
+
* ```
|
|
2059
|
+
*/
|
|
2060
|
+
parse(name: string): Promise<Change>;
|
|
2061
|
+
/**
|
|
2062
|
+
* Validate a change's structure.
|
|
2063
|
+
*
|
|
2064
|
+
* @throws ChangeValidationError if invalid
|
|
2065
|
+
*
|
|
2066
|
+
* @example
|
|
2067
|
+
* ```typescript
|
|
2068
|
+
* ctx.noorm.changes.validate(change)
|
|
2069
|
+
* ```
|
|
2070
|
+
*/
|
|
2071
|
+
validate(change: Change): void;
|
|
2072
|
+
/**
|
|
2073
|
+
* Apply a specific change.
|
|
2074
|
+
*
|
|
2075
|
+
* @example
|
|
2076
|
+
* ```typescript
|
|
2077
|
+
* const result = await ctx.noorm.changes.apply('2024-01-15-add-users')
|
|
2078
|
+
* ```
|
|
2079
|
+
*/
|
|
2080
|
+
apply(name: string, options?: ChangeOptions): Promise<ChangeResult>;
|
|
2081
|
+
/**
|
|
2082
|
+
* Revert a specific change.
|
|
2083
|
+
*
|
|
2084
|
+
* @example
|
|
2085
|
+
* ```typescript
|
|
2086
|
+
* const result = await ctx.noorm.changes.revert('2024-01-15-add-users')
|
|
2087
|
+
* ```
|
|
2088
|
+
*/
|
|
2089
|
+
revert(name: string, options?: ChangeOptions): Promise<ChangeResult>;
|
|
2090
|
+
/**
|
|
2091
|
+
* Apply all pending changes.
|
|
2092
|
+
*
|
|
2093
|
+
* @example
|
|
2094
|
+
* ```typescript
|
|
2095
|
+
* const result = await ctx.noorm.changes.ff()
|
|
2096
|
+
* ```
|
|
2097
|
+
*/
|
|
2098
|
+
ff(): Promise<BatchChangeResult>;
|
|
2099
|
+
/**
|
|
2100
|
+
* Get status of all changes (merged disk + DB).
|
|
2101
|
+
*
|
|
2102
|
+
* @example
|
|
2103
|
+
* ```typescript
|
|
2104
|
+
* const all = await ctx.noorm.changes.status()
|
|
2105
|
+
* ```
|
|
2106
|
+
*/
|
|
2107
|
+
status(): Promise<ChangeListItem[]>;
|
|
2108
|
+
/**
|
|
2109
|
+
* Get only pending (unapplied or reverted) changes.
|
|
2110
|
+
*
|
|
2111
|
+
* @example
|
|
2112
|
+
* ```typescript
|
|
2113
|
+
* const pending = await ctx.noorm.changes.pending()
|
|
2114
|
+
* ```
|
|
2115
|
+
*/
|
|
2116
|
+
pending(): Promise<ChangeListItem[]>;
|
|
2117
|
+
/**
|
|
2118
|
+
* Get execution history.
|
|
2119
|
+
*
|
|
2120
|
+
* @example
|
|
2121
|
+
* ```typescript
|
|
2122
|
+
* const history = await ctx.noorm.changes.history(10)
|
|
2123
|
+
* ```
|
|
2124
|
+
*/
|
|
2125
|
+
history(limit?: number): Promise<ChangeHistoryRecord[]>;
|
|
2126
|
+
}
|
|
2127
|
+
export declare class RunNamespace {
|
|
2128
|
+
#private;
|
|
2129
|
+
constructor(state: ContextState);
|
|
2130
|
+
/**
|
|
2131
|
+
* Discover SQL files in a directory.
|
|
2132
|
+
*
|
|
2133
|
+
* @example
|
|
2134
|
+
* ```typescript
|
|
2135
|
+
* const files = await ctx.noorm.run.discover('sql/')
|
|
2136
|
+
* ```
|
|
2137
|
+
*/
|
|
2138
|
+
discover(dirpath?: string): Promise<string[]>;
|
|
2139
|
+
/**
|
|
2140
|
+
* Preview SQL files — render templates without executing.
|
|
2141
|
+
*
|
|
2142
|
+
* @example
|
|
2143
|
+
* ```typescript
|
|
2144
|
+
* const results = await ctx.noorm.run.preview(['sql/001.sql', 'sql/002.sql'])
|
|
2145
|
+
* ```
|
|
2146
|
+
*/
|
|
2147
|
+
preview(filepaths: string[], output?: string | null): Promise<FileResult[]>;
|
|
2148
|
+
/**
|
|
2149
|
+
* Execute a single SQL file.
|
|
2150
|
+
*
|
|
2151
|
+
* @example
|
|
2152
|
+
* ```typescript
|
|
2153
|
+
* await ctx.noorm.run.file('seeds/test-data.sql')
|
|
2154
|
+
* ```
|
|
2155
|
+
*/
|
|
2156
|
+
file(filepath: string, options?: RunOptions): Promise<FileResult>;
|
|
2157
|
+
/**
|
|
2158
|
+
* Execute multiple SQL files sequentially.
|
|
2159
|
+
*
|
|
2160
|
+
* @example
|
|
2161
|
+
* ```typescript
|
|
2162
|
+
* await ctx.noorm.run.files(['functions/utils.sql', 'triggers/audit.sql'])
|
|
2163
|
+
* ```
|
|
2164
|
+
*/
|
|
2165
|
+
files(filepaths: string[], options?: RunOptions): Promise<BatchResult>;
|
|
2166
|
+
/**
|
|
2167
|
+
* Execute all SQL files in a directory.
|
|
2168
|
+
*
|
|
2169
|
+
* @example
|
|
2170
|
+
* ```typescript
|
|
2171
|
+
* await ctx.noorm.run.dir('seeds/')
|
|
2172
|
+
* ```
|
|
2173
|
+
*/
|
|
2174
|
+
dir(dirpath: string, options?: RunOptions): Promise<BatchResult>;
|
|
2175
|
+
/**
|
|
2176
|
+
* Execute all SQL files in the schema directory.
|
|
2177
|
+
*
|
|
2178
|
+
* @example
|
|
2179
|
+
* ```typescript
|
|
2180
|
+
* await ctx.noorm.run.build({ force: true })
|
|
2181
|
+
* ```
|
|
2182
|
+
*/
|
|
2183
|
+
build(options?: BuildOptions): Promise<BatchResult>;
|
|
923
2184
|
}
|
|
924
2185
|
/**
|
|
925
|
-
*
|
|
2186
|
+
* Overview counts for all categories.
|
|
926
2187
|
*/
|
|
927
|
-
export interface
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
2188
|
+
export interface ExploreOverview {
|
|
2189
|
+
tables: number;
|
|
2190
|
+
views: number;
|
|
2191
|
+
procedures: number;
|
|
2192
|
+
functions: number;
|
|
2193
|
+
types: number;
|
|
2194
|
+
indexes: number;
|
|
2195
|
+
foreignKeys: number;
|
|
2196
|
+
triggers: number;
|
|
2197
|
+
locks: number;
|
|
2198
|
+
connections: number;
|
|
932
2199
|
}
|
|
933
2200
|
/**
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
* WHY: Specific error types allow callers to handle lock failures
|
|
937
|
-
* differently from other errors (e.g., prompt user to wait vs retry).
|
|
2201
|
+
* Table summary for list display.
|
|
938
2202
|
*/
|
|
2203
|
+
export interface TableSummary {
|
|
2204
|
+
name: string;
|
|
2205
|
+
schema?: string;
|
|
2206
|
+
columnCount: number;
|
|
2207
|
+
rowCountEstimate?: number;
|
|
2208
|
+
}
|
|
939
2209
|
/**
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
* Thrown when another process holds the lock and wait=false,
|
|
943
|
-
* or when waitTimeout is exceeded.
|
|
944
|
-
*
|
|
945
|
-
* @example
|
|
946
|
-
* ```typescript
|
|
947
|
-
* const [lock, err] = await attempt(() => lockManager.acquire(config, identity))
|
|
948
|
-
* if (err instanceof LockAcquireError) {
|
|
949
|
-
* console.log(`Blocked by ${err.holder} since ${err.heldSince}`)
|
|
950
|
-
* }
|
|
951
|
-
* ```
|
|
2210
|
+
* Index summary for list display.
|
|
952
2211
|
*/
|
|
953
|
-
export
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
2212
|
+
export interface IndexSummary {
|
|
2213
|
+
name: string;
|
|
2214
|
+
schema?: string;
|
|
2215
|
+
tableName: string;
|
|
2216
|
+
tableSchema?: string;
|
|
2217
|
+
columns: string[];
|
|
2218
|
+
isUnique: boolean;
|
|
2219
|
+
isPrimary: boolean;
|
|
961
2220
|
}
|
|
962
2221
|
/**
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
* Thrown when validating lock before a critical operation
|
|
966
|
-
* and discovering it has expired.
|
|
967
|
-
*
|
|
968
|
-
* @example
|
|
969
|
-
* ```typescript
|
|
970
|
-
* // Before committing transaction
|
|
971
|
-
* const [, err] = await attempt(() => lockManager.validate(configName, identity))
|
|
972
|
-
* if (err instanceof LockExpiredError) {
|
|
973
|
-
* await transaction.rollback()
|
|
974
|
-
* throw new Error('Lock expired, operation aborted')
|
|
975
|
-
* }
|
|
976
|
-
* ```
|
|
2222
|
+
* Foreign key summary for list display.
|
|
977
2223
|
*/
|
|
978
|
-
export
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
2224
|
+
export interface ForeignKeySummary {
|
|
2225
|
+
name: string;
|
|
2226
|
+
schema?: string;
|
|
2227
|
+
tableName: string;
|
|
2228
|
+
tableSchema?: string;
|
|
2229
|
+
columns: string[];
|
|
2230
|
+
referencedTable: string;
|
|
2231
|
+
referencedSchema?: string;
|
|
2232
|
+
referencedColumns: string[];
|
|
2233
|
+
onDelete?: string;
|
|
2234
|
+
onUpdate?: string;
|
|
984
2235
|
}
|
|
985
2236
|
/**
|
|
986
|
-
*
|
|
2237
|
+
* Column detail for tables/views.
|
|
2238
|
+
*/
|
|
2239
|
+
export interface ColumnDetail {
|
|
2240
|
+
name: string;
|
|
2241
|
+
dataType: string;
|
|
2242
|
+
isNullable: boolean;
|
|
2243
|
+
defaultValue?: string;
|
|
2244
|
+
isPrimaryKey: boolean;
|
|
2245
|
+
ordinalPosition: number;
|
|
2246
|
+
}
|
|
2247
|
+
/**
|
|
2248
|
+
* Full table detail.
|
|
987
2249
|
*/
|
|
988
|
-
interface
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
*/
|
|
996
|
-
isTemplate: boolean;
|
|
997
|
-
/**
|
|
998
|
-
* Render duration in milliseconds (only for templates).
|
|
999
|
-
*/
|
|
1000
|
-
durationMs?: number;
|
|
2250
|
+
export interface TableDetail {
|
|
2251
|
+
name: string;
|
|
2252
|
+
schema?: string;
|
|
2253
|
+
columns: ColumnDetail[];
|
|
2254
|
+
indexes: IndexSummary[];
|
|
2255
|
+
foreignKeys: ForeignKeySummary[];
|
|
2256
|
+
rowCountEstimate?: number;
|
|
1001
2257
|
}
|
|
1002
2258
|
/**
|
|
1003
|
-
*
|
|
2259
|
+
* Teardown Types
|
|
1004
2260
|
*
|
|
1005
|
-
*
|
|
2261
|
+
* Types for database reset and teardown operations.
|
|
2262
|
+
* Supports data wipe (truncate) and schema teardown (drop).
|
|
1006
2263
|
*/
|
|
1007
2264
|
/**
|
|
1008
|
-
* Options for
|
|
2265
|
+
* Options for truncating table data.
|
|
1009
2266
|
*
|
|
1010
2267
|
* @example
|
|
1011
2268
|
* ```typescript
|
|
1012
|
-
* //
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
* const ctx = await createContext({
|
|
1017
|
-
* config: 'test',
|
|
1018
|
-
* requireTest: true,
|
|
2269
|
+
* // Truncate all tables except preserved ones from settings
|
|
2270
|
+
* await truncateData(db, 'postgres', {
|
|
2271
|
+
* preserve: ['AppSettings', 'UserRoles'],
|
|
2272
|
+
* restartIdentity: true,
|
|
1019
2273
|
* })
|
|
1020
2274
|
*
|
|
1021
|
-
* //
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
* allowProtected: true,
|
|
2275
|
+
* // Truncate only specific tables
|
|
2276
|
+
* await truncateData(db, 'postgres', {
|
|
2277
|
+
* only: ['users', 'posts'],
|
|
1025
2278
|
* })
|
|
1026
|
-
*
|
|
1027
|
-
* // Env-only mode (CI/CD) - no stored config needed
|
|
1028
|
-
* // Requires NOORM_CONNECTION_DIALECT and NOORM_CONNECTION_DATABASE
|
|
1029
|
-
* const ctx = await createContext()
|
|
1030
|
-
*
|
|
1031
|
-
* // Override stored config via NOORM_* env vars
|
|
1032
|
-
* // NOORM_CONNECTION_HOST=override.host
|
|
1033
|
-
* const ctx = await createContext({ config: 'prod' })
|
|
1034
2279
|
* ```
|
|
1035
2280
|
*/
|
|
1036
|
-
export interface
|
|
1037
|
-
/**
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
config?: string;
|
|
1046
|
-
/** Project root directory. Defaults to process.cwd() */
|
|
1047
|
-
projectRoot?: string;
|
|
1048
|
-
/** Refuse if config.isTest !== true. Default: false */
|
|
1049
|
-
requireTest?: boolean;
|
|
1050
|
-
/** Allow destructive ops on protected configs. Default: false */
|
|
1051
|
-
allowProtected?: boolean;
|
|
1052
|
-
/** Stage name for stage defaults (from settings.yml) */
|
|
1053
|
-
stage?: string;
|
|
1054
|
-
}
|
|
1055
|
-
/**
|
|
1056
|
-
* Result of an execute() call.
|
|
1057
|
-
*/
|
|
1058
|
-
export interface ExecuteResult {
|
|
1059
|
-
/** Number of rows affected (if available) */
|
|
1060
|
-
rowsAffected?: number;
|
|
2281
|
+
export interface TruncateOptions {
|
|
2282
|
+
/** Tables to preserve (won't be truncated) */
|
|
2283
|
+
preserve?: string[];
|
|
2284
|
+
/** If set, only truncate these tables (inverse of preserve) */
|
|
2285
|
+
only?: string[];
|
|
2286
|
+
/** Restart identity/auto-increment sequences (default: true) */
|
|
2287
|
+
restartIdentity?: boolean;
|
|
2288
|
+
/** Dry run - return SQL without executing */
|
|
2289
|
+
dryRun?: boolean;
|
|
1061
2290
|
}
|
|
1062
2291
|
/**
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
* @example
|
|
1066
|
-
* ```typescript
|
|
1067
|
-
* await ctx.transaction(async (tx) => {
|
|
1068
|
-
* const [user] = await tx.query('SELECT * FROM users WHERE id = $1', [id])
|
|
1069
|
-
* await tx.execute('UPDATE users SET login_count = login_count + 1 WHERE id = $1', [id])
|
|
1070
|
-
* return user
|
|
1071
|
-
* })
|
|
1072
|
-
* ```
|
|
2292
|
+
* Result of a truncate operation.
|
|
1073
2293
|
*/
|
|
1074
|
-
export interface
|
|
1075
|
-
/**
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
/**
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
2294
|
+
export interface TruncateResult {
|
|
2295
|
+
/** Tables that were truncated */
|
|
2296
|
+
truncated: string[];
|
|
2297
|
+
/** Tables that were preserved */
|
|
2298
|
+
preserved: string[];
|
|
2299
|
+
/** SQL statements executed (or would execute in dry-run) */
|
|
2300
|
+
statements: string[];
|
|
2301
|
+
/** Duration in milliseconds */
|
|
2302
|
+
durationMs: number;
|
|
1083
2303
|
}
|
|
1084
2304
|
/**
|
|
1085
|
-
*
|
|
2305
|
+
* Result of a teardown operation.
|
|
1086
2306
|
*/
|
|
1087
|
-
export interface
|
|
1088
|
-
/**
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
listener: Function;
|
|
1097
|
-
} | undefined): void;
|
|
1098
|
-
}
|
|
1099
|
-
type RgxEmitData<Shape> = {
|
|
1100
|
-
event: Events<Shape>;
|
|
1101
|
-
data: Shape[Events<Shape>];
|
|
1102
|
-
};
|
|
1103
|
-
type Cleanup = () => void;
|
|
1104
|
-
type Component<Ev extends Record<string, any>> = {
|
|
1105
|
-
on: ObserverEngine<Ev>["on"];
|
|
1106
|
-
once: ObserverEngine<Ev>["once"];
|
|
1107
|
-
emit: ObserverEngine<Ev>["emit"];
|
|
1108
|
-
off: ObserverEngine<Ev>["off"];
|
|
1109
|
-
};
|
|
1110
|
-
type Child<C, Ev extends Record<string, any>> = C & Component<Ev> & {
|
|
1111
|
-
cleanup: Cleanup;
|
|
1112
|
-
clear: Cleanup;
|
|
1113
|
-
};
|
|
1114
|
-
type Instance<Ev extends Record<string, any>> = Component<Ev> & {
|
|
1115
|
-
observe: ObserverEngine<Ev>["observe"];
|
|
1116
|
-
$observer: ObserverEngine<Ev>;
|
|
1117
|
-
};
|
|
1118
|
-
type FuncName = "on" | "once" | "off" | "emit" | "cleanup";
|
|
1119
|
-
type SpyAction<Ev extends Record<string, any>> = {
|
|
1120
|
-
event: keyof Ev | RegExp | "*";
|
|
1121
|
-
listener?: Function | null | undefined;
|
|
1122
|
-
data?: unknown | undefined;
|
|
1123
|
-
fn: FuncName;
|
|
1124
|
-
context: ObserverEngine<Ev>;
|
|
1125
|
-
};
|
|
1126
|
-
interface Spy<Ev extends Record<string, any>> {
|
|
1127
|
-
(action: SpyAction<Ev>): void;
|
|
1128
|
-
}
|
|
1129
|
-
interface EmitValidator<Ev extends Record<string, any>> {
|
|
1130
|
-
(event: keyof Ev, data: Ev[keyof Ev], context: ObserverEngine<Ev>): void;
|
|
1131
|
-
(event: RegExp, data: unknown, context: ObserverEngine<Ev>): void;
|
|
1132
|
-
(event: "*", data: unknown, context: ObserverEngine<Ev>): void;
|
|
1133
|
-
}
|
|
1134
|
-
type Options<Ev extends Record<string, any>> = {
|
|
1135
|
-
name?: string | undefined;
|
|
1136
|
-
spy?: Spy<Ev> | undefined;
|
|
1137
|
-
emitValidator?: EmitValidator<Ev> | undefined;
|
|
1138
|
-
signal?: AbortSignal | undefined;
|
|
1139
|
-
};
|
|
1140
|
-
type ListenerOptions = {
|
|
1141
|
-
signal?: AbortSignal | undefined;
|
|
2307
|
+
export interface TeardownResult {
|
|
2308
|
+
/** Objects dropped by category */
|
|
2309
|
+
dropped: {
|
|
2310
|
+
tables: string[];
|
|
2311
|
+
views: string[];
|
|
2312
|
+
functions: string[];
|
|
2313
|
+
procedures: string[];
|
|
2314
|
+
types: string[];
|
|
2315
|
+
foreignKeys: string[];
|
|
1142
2316
|
};
|
|
1143
|
-
|
|
1144
|
-
|
|
2317
|
+
/** Objects preserved */
|
|
2318
|
+
preserved: string[];
|
|
2319
|
+
/** SQL statements executed (or would execute in dry-run) */
|
|
2320
|
+
statements: string[];
|
|
2321
|
+
/** Duration in milliseconds */
|
|
2322
|
+
durationMs: number;
|
|
2323
|
+
/** Post-script execution result (if any) */
|
|
2324
|
+
postScriptResult?: {
|
|
2325
|
+
executed: boolean;
|
|
2326
|
+
error?: string;
|
|
1145
2327
|
};
|
|
2328
|
+
/** Number of changes marked as stale (if configName provided) */
|
|
2329
|
+
staleCount?: number;
|
|
2330
|
+
/** ID of the reset record created (if configName provided) */
|
|
2331
|
+
resetRecordId?: number;
|
|
1146
2332
|
}
|
|
1147
2333
|
/**
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
1150
|
-
* Enables consistent typing across utility functions and higher-order functions
|
|
1151
|
-
* where function parameters need to be strongly typed.
|
|
1152
|
-
*
|
|
1153
|
-
* @example
|
|
1154
|
-
* function memoize<A extends any[], R>(fn: Func<A, R>): Func<A, R>
|
|
1155
|
-
* function debounce<A extends any[]>(fn: Func<A, void>, ms: number): Func<A, void>
|
|
1156
|
-
*/
|
|
1157
|
-
export type Func<A extends any[] = any[], R = any> = (...args: A) => R;
|
|
1158
|
-
/**
|
|
1159
|
-
* Represents a value that can be either synchronous or asynchronous.
|
|
1160
|
-
*
|
|
1161
|
-
* Critical for utility functions that need to handle both sync and async
|
|
1162
|
-
* operations uniformly, enabling flexible API design.
|
|
1163
|
-
*
|
|
1164
|
-
* @example
|
|
1165
|
-
* function processData<T>(processor: () => MaybePromise<T>): Promise<T>
|
|
1166
|
-
* function transform<T, U>(value: T, transformer: (val: T) => MaybePromise<U>): Promise<U>
|
|
2334
|
+
* Preview of what would be affected by teardown.
|
|
1167
2335
|
*/
|
|
1168
|
-
export
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
[Symbol.asyncIterator](): AsyncGenerator<Awaited<EventData<S, E>>, undefined, unknown>;
|
|
1178
|
-
get lastValue(): E extends Events<S> ? S[E] : E extends RegExp ? ObserverEngine.RgxEmitData<S> : S[Events<S>];
|
|
1179
|
-
get done(): boolean;
|
|
1180
|
-
emit(data?: (E extends Events<S> ? S[E] : S[Events<S>])): void;
|
|
1181
|
-
}
|
|
1182
|
-
declare class ObserverEngine<Shape extends Record<string, any> = Record<string, any>> {
|
|
1183
|
-
#private;
|
|
1184
|
-
constructor(options?: ObserverEngine.Options<Shape>);
|
|
1185
|
-
name: string;
|
|
1186
|
-
/**
|
|
1187
|
-
* Returns facts about the the internal state of the observable instance.
|
|
1188
|
-
*/
|
|
1189
|
-
$facts(): {
|
|
1190
|
-
listeners: (keyof Shape)[];
|
|
1191
|
-
rgxListeners: string[];
|
|
1192
|
-
listenerCounts: Record<string, number>;
|
|
1193
|
-
hasSpy: boolean;
|
|
1194
|
-
};
|
|
1195
|
-
/**
|
|
1196
|
-
* The internals of the observable instance.
|
|
1197
|
-
*
|
|
1198
|
-
* NOTE: Do not use this to try to meddle with the
|
|
1199
|
-
* internals of the observable instance. This is for
|
|
1200
|
-
* debugging purposes only.
|
|
1201
|
-
*/
|
|
1202
|
-
$internals(): {
|
|
1203
|
-
listenerMap: Map<keyof Shape, Set<Func>>;
|
|
1204
|
-
rgxListenerMap: Map<string, Set<Func>>;
|
|
1205
|
-
internalListener: EventTarget;
|
|
1206
|
-
name: string;
|
|
1207
|
-
spy: ObserverEngine.Spy<Shape> | undefined;
|
|
2336
|
+
export interface TeardownPreview {
|
|
2337
|
+
/** Objects that would be dropped */
|
|
2338
|
+
toDrop: {
|
|
2339
|
+
tables: string[];
|
|
2340
|
+
views: string[];
|
|
2341
|
+
functions: string[];
|
|
2342
|
+
procedures: string[];
|
|
2343
|
+
types: string[];
|
|
2344
|
+
foreignKeys: string[];
|
|
1208
2345
|
};
|
|
2346
|
+
/** Objects that would be preserved */
|
|
2347
|
+
toPreserve: string[];
|
|
2348
|
+
/** SQL statements that would execute */
|
|
2349
|
+
statements: string[];
|
|
2350
|
+
}
|
|
2351
|
+
export declare class DbNamespace {
|
|
2352
|
+
#private;
|
|
2353
|
+
constructor(state: ContextState);
|
|
1209
2354
|
/**
|
|
1210
|
-
*
|
|
1211
|
-
*/
|
|
1212
|
-
$has(event: Events<Shape>): boolean;
|
|
1213
|
-
/**
|
|
1214
|
-
* Returns if the observable instance has a regex event
|
|
1215
|
-
*/
|
|
1216
|
-
$has(event: RegExp): boolean;
|
|
1217
|
-
/**
|
|
1218
|
-
* Returns if the observable instance has the given event
|
|
1219
|
-
*/
|
|
1220
|
-
$has(event: string): boolean;
|
|
1221
|
-
/**
|
|
1222
|
-
* Enables or disables debugging for the observable instance.
|
|
1223
|
-
* Works in conjunction with your spy function. Provides a
|
|
1224
|
-
* stack trace of events that are triggered, listened to, and
|
|
1225
|
-
* cleaned up.
|
|
1226
|
-
*
|
|
1227
|
-
* @param on Whether to enable or disable debugging
|
|
1228
|
-
*/
|
|
1229
|
-
debug(on?: boolean): void;
|
|
1230
|
-
/**
|
|
1231
|
-
* Sets the spy function for the observable instance.
|
|
1232
|
-
* @param spy The spy function to set
|
|
1233
|
-
* @param force Whether to force the spy function to be set even if one is already set
|
|
1234
|
-
*/
|
|
1235
|
-
spy(spy: ObserverEngine.Spy<Shape>, force?: boolean): void;
|
|
1236
|
-
/**
|
|
1237
|
-
* Observes given component as an extension of this observable instance.
|
|
1238
|
-
* @param component Component to wrap events around
|
|
1239
|
-
* @param options Optional configuration including signal for cleanup
|
|
2355
|
+
* List all tables in the database.
|
|
1240
2356
|
*
|
|
1241
2357
|
* @example
|
|
1242
|
-
*
|
|
1243
|
-
* const
|
|
1244
|
-
*
|
|
1245
|
-
* const modal = {};
|
|
1246
|
-
*
|
|
1247
|
-
* obs.observe(modal);
|
|
1248
|
-
*
|
|
1249
|
-
* modal.on('modal-open', () => {});
|
|
1250
|
-
*
|
|
1251
|
-
* obs.trigger('modal-open'); // opens modal
|
|
1252
|
-
* modal.trigger('modal-open'); // opens modal
|
|
1253
|
-
*
|
|
1254
|
-
* modal.cleanup(); // clears all event listeners
|
|
2358
|
+
* ```typescript
|
|
2359
|
+
* const tables = await ctx.noorm.db.listTables()
|
|
2360
|
+
* ```
|
|
1255
2361
|
*/
|
|
1256
|
-
|
|
2362
|
+
listTables(): Promise<TableSummary[]>;
|
|
1257
2363
|
/**
|
|
1258
|
-
*
|
|
2364
|
+
* Get detailed information about a table.
|
|
1259
2365
|
*
|
|
1260
2366
|
* @example
|
|
1261
|
-
*
|
|
1262
|
-
* const
|
|
1263
|
-
*
|
|
1264
|
-
* const something = obs.on('something');
|
|
1265
|
-
* const data = await something.next(); // waits for next event
|
|
1266
|
-
* something.emit('special'); // emits data to listeners
|
|
1267
|
-
*
|
|
1268
|
-
* something.cleanup(); // stops listening for events
|
|
2367
|
+
* ```typescript
|
|
2368
|
+
* const detail = await ctx.noorm.db.describeTable('users')
|
|
2369
|
+
* ```
|
|
1269
2370
|
*/
|
|
1270
|
-
|
|
1271
|
-
on<E extends string>(event: E, options?: ObserverEngine.ListenerOptions): EventGenerator<Record<E, any>>;
|
|
2371
|
+
describeTable(name: string, schema?: string): Promise<TableDetail | null>;
|
|
1272
2372
|
/**
|
|
1273
|
-
*
|
|
2373
|
+
* Get database overview with counts of all object types.
|
|
1274
2374
|
*
|
|
1275
2375
|
* @example
|
|
1276
|
-
*
|
|
1277
|
-
* const
|
|
1278
|
-
*
|
|
1279
|
-
* obs.on('something', (data) => {
|
|
1280
|
-
* console.log(data);
|
|
1281
|
-
* });
|
|
2376
|
+
* ```typescript
|
|
2377
|
+
* const overview = await ctx.noorm.db.overview()
|
|
2378
|
+
* ```
|
|
1282
2379
|
*/
|
|
1283
|
-
|
|
1284
|
-
on<E extends string>(event: E, listener: ObserverEngine.EventCallback<Record<E, any>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
2380
|
+
overview(): Promise<ExploreOverview>;
|
|
1285
2381
|
/**
|
|
1286
|
-
*
|
|
2382
|
+
* Preview what teardown would drop without executing.
|
|
1287
2383
|
*
|
|
1288
2384
|
* @example
|
|
1289
|
-
*
|
|
1290
|
-
* const
|
|
1291
|
-
*
|
|
1292
|
-
* const onEvent = obs.on(/some/);
|
|
1293
|
-
* const { event, data } = await onEvent.next(); // waits for next event
|
|
1294
|
-
* onEvent.emit('something'); // emits data to listeners
|
|
1295
|
-
*
|
|
1296
|
-
* onEvent.cleanup(); // stops listening for events
|
|
2385
|
+
* ```typescript
|
|
2386
|
+
* const preview = await ctx.noorm.db.previewTeardown()
|
|
2387
|
+
* ```
|
|
1297
2388
|
*/
|
|
1298
|
-
|
|
2389
|
+
previewTeardown(): Promise<TeardownPreview>;
|
|
1299
2390
|
/**
|
|
1300
|
-
*
|
|
2391
|
+
* Wipe all data, keeping the schema intact.
|
|
2392
|
+
*
|
|
2393
|
+
* User-provided preserve/only options take priority.
|
|
2394
|
+
* Falls back to settings.teardown.preserveTables from settings.yml.
|
|
1301
2395
|
*
|
|
1302
2396
|
* @example
|
|
2397
|
+
* ```typescript
|
|
2398
|
+
* // Uses preserve list from settings.yml automatically
|
|
2399
|
+
* const result = await ctx.noorm.db.truncate()
|
|
1303
2400
|
*
|
|
1304
|
-
*
|
|
2401
|
+
* // Override with explicit preserve list
|
|
2402
|
+
* const result = await ctx.noorm.db.truncate({ preserve: ['seeds'] })
|
|
1305
2403
|
*
|
|
1306
|
-
*
|
|
1307
|
-
*
|
|
1308
|
-
*
|
|
1309
|
-
*/
|
|
1310
|
-
on(event: RegExp, listener: ObserverEngine.EventCallback<ObserverEngine.RgxEmitData<Shape>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
1311
|
-
/**
|
|
1312
|
-
* Returns an event promise that resolves when
|
|
1313
|
-
* the specified event is emitted
|
|
2404
|
+
* // Truncate only specific tables
|
|
2405
|
+
* const result = await ctx.noorm.db.truncate({ only: ['users', 'posts'] })
|
|
2406
|
+
* ```
|
|
1314
2407
|
*/
|
|
1315
|
-
|
|
1316
|
-
/**
|
|
1317
|
-
* Returns an event promise that resolves when
|
|
1318
|
-
* the specified event is emitted. This overload
|
|
1319
|
-
* is untyped and can be used to listen for any
|
|
1320
|
-
* event that is emitted.
|
|
1321
|
-
*/
|
|
1322
|
-
once<E extends string>(event: E, options?: ObserverEngine.ListenerOptions): EventPromise<Record<E, any>>;
|
|
1323
|
-
/**
|
|
1324
|
-
* Executes a callback once when the specified
|
|
1325
|
-
* event is emitted
|
|
1326
|
-
*/
|
|
1327
|
-
once<E extends Events<Shape>>(event: E, listener: ObserverEngine.EventCallback<Shape[E]>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
1328
|
-
/**
|
|
1329
|
-
* Executes a callback once when the specified
|
|
1330
|
-
* event is emitted. This overload is untyped
|
|
1331
|
-
* and can be used to listen for any event that
|
|
1332
|
-
* is emitted.
|
|
1333
|
-
*/
|
|
1334
|
-
once<E extends string>(event: E, listener: ObserverEngine.EventCallback<Record<E, any>>, options?: ObserverEngine.ListenerOptions): ObserverEngine.Cleanup;
|
|
1335
|
-
/**
|
|
1336
|
-
* Returns an event promise that resolves when
|
|
1337
|
-
* any events matching the regex are emitted
|
|
1338
|
-
*/
|
|
1339
|
-
once(event: RegExp, options?: ObserverEngine.ListenerOptions): EventPromise<ObserverEngine.RgxEmitData<Shape>>;
|
|
2408
|
+
truncate(options?: TruncateOptions): Promise<TruncateResult>;
|
|
1340
2409
|
/**
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
2410
|
+
* Drop all database objects except noorm tracking tables.
|
|
2411
|
+
*
|
|
2412
|
+
* @example
|
|
2413
|
+
* ```typescript
|
|
2414
|
+
* const result = await ctx.noorm.db.teardown()
|
|
2415
|
+
* ```
|
|
1343
2416
|
*/
|
|
1344
|
-
|
|
2417
|
+
teardown(): Promise<TeardownResult>;
|
|
1345
2418
|
/**
|
|
1346
|
-
*
|
|
1347
|
-
*
|
|
1348
|
-
* @
|
|
2419
|
+
* Full rebuild: teardown + build.
|
|
2420
|
+
*
|
|
2421
|
+
* @example
|
|
2422
|
+
* ```typescript
|
|
2423
|
+
* await ctx.noorm.db.reset()
|
|
2424
|
+
* ```
|
|
1349
2425
|
*/
|
|
1350
|
-
|
|
1351
|
-
/**
|
|
1352
|
-
|
|
1353
|
-
clear(): void;
|
|
1354
|
-
queue<E extends Events<Shape> | RegExp>(event: E, process: (data: EventData<Shape, E>) => MaybePromise<any>, options: QueueOpts): EventQueue<Shape, E>;
|
|
1355
|
-
}
|
|
1356
|
-
export type EventData<S, E extends Events<S> | RegExp = Events<S>> = (E extends Events<S> ? S[E] : E extends RegExp ? ObserverEngine.RgxEmitData<S> : S[Events<S>]);
|
|
1357
|
-
declare class EventPromise<T> extends Promise<T> {
|
|
1358
|
-
cleanup?: () => void;
|
|
1359
|
-
reject?: (err: Error | string) => void;
|
|
1360
|
-
resolve?: (value: T) => void;
|
|
1361
|
-
}
|
|
1362
|
-
declare class InternalQueueEvent<T = unknown> {
|
|
1363
|
-
readonly data: T;
|
|
1364
|
-
constructor(data: T);
|
|
1365
|
-
}
|
|
1366
|
-
declare enum QueueRejectionReason {
|
|
1367
|
-
full = "Queue is full",
|
|
1368
|
-
notRunning = "Queue is not running"
|
|
2426
|
+
reset(): Promise<void>;
|
|
2427
|
+
/** @internal Used by NoormOps to wire up reset -> build. */
|
|
2428
|
+
set _buildFn(fn: (opts?: BuildOptions) => Promise<unknown>);
|
|
1369
2429
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
};
|
|
1399
|
-
error: QueueEventData<S, E> & {
|
|
1400
|
-
error: Error;
|
|
1401
|
-
rateLimited: boolean;
|
|
1402
|
-
};
|
|
1403
|
-
timeout: QueueEventData<S, E> & {
|
|
1404
|
-
error: Error;
|
|
1405
|
-
rateLimited: boolean;
|
|
1406
|
-
};
|
|
1407
|
-
rejected: QueueEventData<S, E> & {
|
|
1408
|
-
reason: QueueRejectionReason;
|
|
1409
|
-
};
|
|
1410
|
-
"rate-limited": QueueEventData<S, E> & {
|
|
1411
|
-
rateLimited: boolean;
|
|
1412
|
-
};
|
|
1413
|
-
empty: void;
|
|
1414
|
-
idle: void;
|
|
1415
|
-
drain: {
|
|
1416
|
-
pending: number;
|
|
1417
|
-
};
|
|
1418
|
-
drained: {
|
|
1419
|
-
pending?: number;
|
|
1420
|
-
drained?: number;
|
|
1421
|
-
};
|
|
1422
|
-
flush: {
|
|
1423
|
-
pending: number;
|
|
1424
|
-
};
|
|
1425
|
-
flushed: {
|
|
1426
|
-
flushed: number;
|
|
1427
|
-
};
|
|
1428
|
-
paused: void;
|
|
1429
|
-
resumed: void;
|
|
1430
|
-
cleanup: void;
|
|
1431
|
-
purged: {
|
|
1432
|
-
count: number;
|
|
1433
|
-
};
|
|
1434
|
-
shutdown: {
|
|
1435
|
-
force: boolean;
|
|
1436
|
-
pending?: number;
|
|
1437
|
-
};
|
|
1438
|
-
};
|
|
1439
|
-
declare enum QueueState {
|
|
1440
|
-
running = "running",
|
|
1441
|
-
paused = "paused",
|
|
1442
|
-
stopped = "stopped",
|
|
1443
|
-
draining = "draining"
|
|
2430
|
+
/**
|
|
2431
|
+
* Lock manager types.
|
|
2432
|
+
*
|
|
2433
|
+
* Defines the shape of locks and options for acquiring them.
|
|
2434
|
+
* Used to prevent concurrent operations on the same database.
|
|
2435
|
+
*
|
|
2436
|
+
* WHY: Concurrent DDL operations can corrupt database state.
|
|
2437
|
+
* Locks ensure only one process modifies the schema at a time.
|
|
2438
|
+
*/
|
|
2439
|
+
/**
|
|
2440
|
+
* Lock state returned after acquisition.
|
|
2441
|
+
*
|
|
2442
|
+
* @example
|
|
2443
|
+
* ```typescript
|
|
2444
|
+
* const lock = await lockManager.acquire('dev', 'alice@example.com')
|
|
2445
|
+
* console.log(lock.lockedBy) // 'alice@example.com'
|
|
2446
|
+
* console.log(lock.expiresAt) // Date object
|
|
2447
|
+
* ```
|
|
2448
|
+
*/
|
|
2449
|
+
interface Lock$1 {
|
|
2450
|
+
/** Identity string of holder */
|
|
2451
|
+
lockedBy: string;
|
|
2452
|
+
/** When acquired */
|
|
2453
|
+
lockedAt: Date;
|
|
2454
|
+
/** Auto-expiry time */
|
|
2455
|
+
expiresAt: Date;
|
|
2456
|
+
/** Optional reason for acquiring */
|
|
2457
|
+
reason?: string;
|
|
1444
2458
|
}
|
|
1445
2459
|
/**
|
|
1446
|
-
*
|
|
2460
|
+
* Options for acquiring a lock.
|
|
2461
|
+
*
|
|
2462
|
+
* @example
|
|
2463
|
+
* ```typescript
|
|
2464
|
+
* // Wait up to 30s for lock, polling every 500ms
|
|
2465
|
+
* const options: LockOptions = {
|
|
2466
|
+
* timeout: 60_000, // Lock expires after 60s
|
|
2467
|
+
* wait: true, // Block until available
|
|
2468
|
+
* waitTimeout: 30_000, // Max wait time
|
|
2469
|
+
* pollInterval: 500, // Check every 500ms
|
|
2470
|
+
* reason: 'Running migrations',
|
|
2471
|
+
* }
|
|
2472
|
+
* ```
|
|
1447
2473
|
*/
|
|
1448
|
-
|
|
2474
|
+
interface LockOptions$1 {
|
|
1449
2475
|
/**
|
|
1450
|
-
*
|
|
2476
|
+
* Database dialect for date formatting.
|
|
2477
|
+
*
|
|
2478
|
+
* SQLite stores dates as ISO strings, other dialects can use Date objects.
|
|
2479
|
+
* @default 'postgres'
|
|
2480
|
+
*/
|
|
2481
|
+
dialect?: "postgres" | "mysql" | "sqlite" | "mssql";
|
|
2482
|
+
/**
|
|
2483
|
+
* Lock duration in milliseconds.
|
|
2484
|
+
*
|
|
2485
|
+
* After this time, the lock expires and can be claimed by others.
|
|
2486
|
+
* @default 300_000 (5 minutes)
|
|
2487
|
+
*/
|
|
2488
|
+
timeout?: number;
|
|
2489
|
+
/**
|
|
2490
|
+
* Block until lock is available?
|
|
2491
|
+
*
|
|
2492
|
+
* If true, will poll until the lock is acquired or waitTimeout is reached.
|
|
2493
|
+
* @default false
|
|
1451
2494
|
*/
|
|
1452
|
-
|
|
2495
|
+
wait?: boolean;
|
|
1453
2496
|
/**
|
|
1454
|
-
*
|
|
2497
|
+
* Max time to wait for lock in milliseconds.
|
|
1455
2498
|
*
|
|
1456
|
-
*
|
|
2499
|
+
* Only used if wait is true.
|
|
2500
|
+
* @default 30_000 (30 seconds)
|
|
1457
2501
|
*/
|
|
1458
|
-
|
|
2502
|
+
waitTimeout?: number;
|
|
1459
2503
|
/**
|
|
1460
|
-
*
|
|
2504
|
+
* How often to poll when waiting, in milliseconds.
|
|
1461
2505
|
*
|
|
1462
|
-
*
|
|
2506
|
+
* Only used if wait is true.
|
|
2507
|
+
* @default 1_000 (1 second)
|
|
1463
2508
|
*/
|
|
1464
|
-
|
|
2509
|
+
pollInterval?: number;
|
|
1465
2510
|
/**
|
|
1466
|
-
*
|
|
1467
|
-
* check for new items after idle.
|
|
2511
|
+
* Optional reason for acquiring the lock.
|
|
1468
2512
|
*
|
|
1469
|
-
*
|
|
2513
|
+
* Shown to users who are blocked by this lock.
|
|
1470
2514
|
*/
|
|
1471
|
-
|
|
2515
|
+
reason?: string;
|
|
2516
|
+
}
|
|
2517
|
+
/**
|
|
2518
|
+
* Result of a lock status check.
|
|
2519
|
+
*/
|
|
2520
|
+
export interface LockStatus {
|
|
2521
|
+
/** Whether the lock is currently held */
|
|
2522
|
+
isLocked: boolean;
|
|
2523
|
+
/** Lock details if held, null if not */
|
|
2524
|
+
lock: Lock$1 | null;
|
|
2525
|
+
}
|
|
2526
|
+
/**
|
|
2527
|
+
* Lock-related errors.
|
|
2528
|
+
*
|
|
2529
|
+
* WHY: Specific error types allow callers to handle lock failures
|
|
2530
|
+
* differently from other errors (e.g., prompt user to wait vs retry).
|
|
2531
|
+
*/
|
|
2532
|
+
/**
|
|
2533
|
+
* Error when lock cannot be acquired.
|
|
2534
|
+
*
|
|
2535
|
+
* Thrown when another process holds the lock and wait=false,
|
|
2536
|
+
* or when waitTimeout is exceeded.
|
|
2537
|
+
*
|
|
2538
|
+
* @example
|
|
2539
|
+
* ```typescript
|
|
2540
|
+
* const [lock, err] = await attempt(() => lockManager.acquire(config, identity))
|
|
2541
|
+
* if (err instanceof LockAcquireError) {
|
|
2542
|
+
* console.log(`Blocked by ${err.holder} since ${err.heldSince}`)
|
|
2543
|
+
* }
|
|
2544
|
+
* ```
|
|
2545
|
+
*/
|
|
2546
|
+
export declare class LockAcquireError extends Error {
|
|
2547
|
+
readonly configName: string;
|
|
2548
|
+
readonly holder: string;
|
|
2549
|
+
readonly heldSince: Date;
|
|
2550
|
+
readonly expiresAt: Date;
|
|
2551
|
+
readonly reason?: string | undefined;
|
|
2552
|
+
readonly name: "LockAcquireError";
|
|
2553
|
+
constructor(configName: string, holder: string, heldSince: Date, expiresAt: Date, reason?: string | undefined);
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Error when lock expires during operation.
|
|
2557
|
+
*
|
|
2558
|
+
* Thrown when validating lock before a critical operation
|
|
2559
|
+
* and discovering it has expired.
|
|
2560
|
+
*
|
|
2561
|
+
* @example
|
|
2562
|
+
* ```typescript
|
|
2563
|
+
* // Before committing transaction
|
|
2564
|
+
* const [, err] = await attempt(() => lockManager.validate(configName, identity))
|
|
2565
|
+
* if (err instanceof LockExpiredError) {
|
|
2566
|
+
* await transaction.rollback()
|
|
2567
|
+
* throw new Error('Lock expired, operation aborted')
|
|
2568
|
+
* }
|
|
2569
|
+
* ```
|
|
2570
|
+
*/
|
|
2571
|
+
export declare class LockExpiredError extends Error {
|
|
2572
|
+
readonly configName: string;
|
|
2573
|
+
readonly identity: string;
|
|
2574
|
+
readonly expiredAt: Date;
|
|
2575
|
+
readonly name: "LockExpiredError";
|
|
2576
|
+
constructor(configName: string, identity: string, expiredAt: Date);
|
|
2577
|
+
}
|
|
2578
|
+
export declare class LockNamespace {
|
|
2579
|
+
#private;
|
|
2580
|
+
constructor(state: ContextState);
|
|
1472
2581
|
/**
|
|
1473
|
-
*
|
|
1474
|
-
* the next process time. This stops all concurrent
|
|
1475
|
-
* processes from happening at the same time.
|
|
2582
|
+
* Acquire a database lock.
|
|
1476
2583
|
*
|
|
1477
|
-
* @
|
|
1478
|
-
*
|
|
2584
|
+
* @example
|
|
2585
|
+
* ```typescript
|
|
2586
|
+
* const lock = await ctx.noorm.lock.acquire({ timeout: 60000 })
|
|
2587
|
+
* ```
|
|
1479
2588
|
*/
|
|
1480
|
-
|
|
2589
|
+
acquire(options?: LockOptions$1): Promise<Lock$1>;
|
|
1481
2590
|
/**
|
|
1482
|
-
*
|
|
1483
|
-
*
|
|
1484
|
-
* @note If the interval is 0, the queue will not wait between items
|
|
2591
|
+
* Release the current lock.
|
|
1485
2592
|
*
|
|
1486
|
-
* @
|
|
2593
|
+
* @example
|
|
2594
|
+
* ```typescript
|
|
2595
|
+
* await ctx.noorm.lock.release()
|
|
2596
|
+
* ```
|
|
1487
2597
|
*/
|
|
1488
|
-
|
|
2598
|
+
release(): Promise<void>;
|
|
1489
2599
|
/**
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
* @note If the timeout is 0, the task will not be considered timed out
|
|
2600
|
+
* Get current lock status.
|
|
1493
2601
|
*
|
|
1494
|
-
* @
|
|
2602
|
+
* @example
|
|
2603
|
+
* ```typescript
|
|
2604
|
+
* const status = await ctx.noorm.lock.status()
|
|
2605
|
+
* ```
|
|
1495
2606
|
*/
|
|
1496
|
-
|
|
2607
|
+
status(): Promise<LockStatus>;
|
|
1497
2608
|
/**
|
|
1498
|
-
*
|
|
2609
|
+
* Execute an operation with automatic lock acquisition and release.
|
|
1499
2610
|
*
|
|
1500
|
-
* @
|
|
2611
|
+
* @example
|
|
2612
|
+
* ```typescript
|
|
2613
|
+
* await ctx.noorm.lock.withLock(async () => {
|
|
2614
|
+
* await ctx.noorm.run.build()
|
|
2615
|
+
* })
|
|
2616
|
+
* ```
|
|
1501
2617
|
*/
|
|
1502
|
-
|
|
2618
|
+
withLock<T>(fn: () => Promise<T>, options?: LockOptions$1): Promise<T>;
|
|
1503
2619
|
/**
|
|
1504
|
-
*
|
|
2620
|
+
* Force release any database lock regardless of ownership.
|
|
1505
2621
|
*
|
|
1506
|
-
* @
|
|
2622
|
+
* @example
|
|
2623
|
+
* ```typescript
|
|
2624
|
+
* await ctx.noorm.lock.forceRelease()
|
|
2625
|
+
* ```
|
|
1507
2626
|
*/
|
|
1508
|
-
|
|
2627
|
+
forceRelease(): Promise<boolean>;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Vault secret entry (decrypted).
|
|
2631
|
+
*/
|
|
2632
|
+
export interface VaultSecret {
|
|
2633
|
+
/** Secret key name */
|
|
2634
|
+
key: string;
|
|
2635
|
+
/** Decrypted value */
|
|
2636
|
+
value: string;
|
|
2637
|
+
/** Identity who set this secret */
|
|
2638
|
+
setBy: string;
|
|
2639
|
+
/** When created */
|
|
2640
|
+
createdAt: Date;
|
|
2641
|
+
/** When last updated */
|
|
2642
|
+
updatedAt: Date;
|
|
2643
|
+
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Result of vault copy operation.
|
|
2646
|
+
*/
|
|
2647
|
+
export interface VaultCopyResult {
|
|
2648
|
+
/** Keys that were successfully copied */
|
|
2649
|
+
copied: string[];
|
|
2650
|
+
/** Keys that were skipped (already exist and force not set) */
|
|
2651
|
+
skipped: string[];
|
|
2652
|
+
/** Keys that failed with errors */
|
|
2653
|
+
errors: Array<{
|
|
2654
|
+
key: string;
|
|
2655
|
+
error: string;
|
|
2656
|
+
}>;
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Result of vault propagation.
|
|
2660
|
+
*/
|
|
2661
|
+
export interface VaultPropagationResult {
|
|
2662
|
+
/** Identity hashes that received the vault key */
|
|
2663
|
+
propagatedTo: string[];
|
|
2664
|
+
/** Count of users who already had access */
|
|
2665
|
+
alreadyHadAccess: number;
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Vault status for the current user.
|
|
2669
|
+
*/
|
|
2670
|
+
export interface VaultStatus {
|
|
2671
|
+
/** Whether the vault is initialized (at least one user has the vault key) */
|
|
2672
|
+
isInitialized: boolean;
|
|
2673
|
+
/** Whether the current user has access to the vault */
|
|
2674
|
+
hasAccess: boolean;
|
|
2675
|
+
/** Number of secrets in the vault */
|
|
2676
|
+
secretCount: number;
|
|
2677
|
+
/** Number of users with vault access */
|
|
2678
|
+
usersWithAccess: number;
|
|
2679
|
+
/** Number of users without vault access */
|
|
2680
|
+
usersWithoutAccess: number;
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Vault event types.
|
|
2684
|
+
*
|
|
2685
|
+
* All events emitted by the vault module. These are merged into
|
|
2686
|
+
* NoormEvents via the VaultEvents interface.
|
|
2687
|
+
*/
|
|
2688
|
+
/**
|
|
2689
|
+
* Vault events for observer integration.
|
|
2690
|
+
*
|
|
2691
|
+
* Events follow the naming convention `vault:{operation}`.
|
|
2692
|
+
*/
|
|
2693
|
+
export interface VaultEvents {
|
|
2694
|
+
/** Vault was initialized for the first time */
|
|
2695
|
+
"vault:initialized": {
|
|
2696
|
+
identityHash: string;
|
|
2697
|
+
};
|
|
2698
|
+
/** New vault secret was created */
|
|
2699
|
+
"vault:secret:created": {
|
|
2700
|
+
key: string;
|
|
2701
|
+
setBy: string;
|
|
2702
|
+
};
|
|
2703
|
+
/** Existing vault secret was updated */
|
|
2704
|
+
"vault:secret:updated": {
|
|
2705
|
+
key: string;
|
|
2706
|
+
setBy: string;
|
|
2707
|
+
};
|
|
2708
|
+
/** Vault secret was deleted */
|
|
2709
|
+
"vault:secret:deleted": {
|
|
2710
|
+
key: string;
|
|
2711
|
+
};
|
|
2712
|
+
/** Vault key was propagated to a user */
|
|
2713
|
+
"vault:propagated": {
|
|
2714
|
+
toIdentityHash: string;
|
|
2715
|
+
toEmail: string;
|
|
2716
|
+
};
|
|
2717
|
+
/** Vault copy operation started */
|
|
2718
|
+
"vault:copy:starting": {
|
|
2719
|
+
source: string;
|
|
2720
|
+
destination: string;
|
|
2721
|
+
keys: "all" | number;
|
|
2722
|
+
};
|
|
2723
|
+
/** Vault copy operation completed */
|
|
2724
|
+
"vault:copy:completed": {
|
|
2725
|
+
source: string;
|
|
2726
|
+
destination: string;
|
|
2727
|
+
copied: number;
|
|
2728
|
+
skipped: number;
|
|
2729
|
+
errors: number;
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* Options for vault copy operation.
|
|
2734
|
+
*/
|
|
2735
|
+
export interface VaultCopyOptions {
|
|
2736
|
+
/** Overwrite existing secrets in destination (default: false) */
|
|
2737
|
+
force?: boolean;
|
|
2738
|
+
}
|
|
2739
|
+
export declare class VaultNamespace {
|
|
2740
|
+
#private;
|
|
2741
|
+
constructor(state: ContextState);
|
|
1509
2742
|
/**
|
|
1510
|
-
*
|
|
2743
|
+
* Initialize the vault for this database.
|
|
1511
2744
|
*
|
|
1512
|
-
* @
|
|
2745
|
+
* @example
|
|
2746
|
+
* ```typescript
|
|
2747
|
+
* const [vaultKey, err] = await ctx.noorm.vault.init()
|
|
2748
|
+
* ```
|
|
1513
2749
|
*/
|
|
1514
|
-
|
|
2750
|
+
init(): Promise<[
|
|
2751
|
+
Buffer | null,
|
|
2752
|
+
Error | null
|
|
2753
|
+
]>;
|
|
1515
2754
|
/**
|
|
1516
|
-
*
|
|
2755
|
+
* Get vault status.
|
|
1517
2756
|
*
|
|
1518
|
-
* @
|
|
2757
|
+
* @example
|
|
2758
|
+
* ```typescript
|
|
2759
|
+
* const status = await ctx.noorm.vault.status()
|
|
2760
|
+
* ```
|
|
1519
2761
|
*/
|
|
1520
|
-
|
|
2762
|
+
status(): Promise<VaultStatus>;
|
|
1521
2763
|
/**
|
|
1522
|
-
*
|
|
1523
|
-
* get more detailed output.
|
|
2764
|
+
* Set a vault secret.
|
|
1524
2765
|
*
|
|
1525
|
-
* @
|
|
2766
|
+
* @example
|
|
2767
|
+
* ```typescript
|
|
2768
|
+
* const [, err] = await ctx.noorm.vault.set('API_KEY', 'sk-live-...', privateKey)
|
|
2769
|
+
* ```
|
|
1526
2770
|
*/
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
private opts;
|
|
1532
|
-
constructor(opts: QueueOpts & {
|
|
1533
|
-
event: E | RegExp;
|
|
1534
|
-
process: (data: EventData<S, E>) => Promise<void>;
|
|
1535
|
-
observer?: ObserverEngine<S>;
|
|
1536
|
-
});
|
|
2771
|
+
set(key: string, value: string, privateKey: string): Promise<[
|
|
2772
|
+
void,
|
|
2773
|
+
Error | null
|
|
2774
|
+
]>;
|
|
1537
2775
|
/**
|
|
1538
|
-
*
|
|
2776
|
+
* Get a vault secret by key.
|
|
2777
|
+
*
|
|
2778
|
+
* @example
|
|
2779
|
+
* ```typescript
|
|
2780
|
+
* const value = await ctx.noorm.vault.get('API_KEY', privateKey)
|
|
2781
|
+
* ```
|
|
1539
2782
|
*/
|
|
1540
|
-
|
|
2783
|
+
get(key: string, privateKey: string): Promise<string | null>;
|
|
1541
2784
|
/**
|
|
1542
|
-
*
|
|
2785
|
+
* Get all vault secrets.
|
|
2786
|
+
*
|
|
2787
|
+
* @example
|
|
2788
|
+
* ```typescript
|
|
2789
|
+
* const all = await ctx.noorm.vault.getAll(privateKey)
|
|
2790
|
+
* ```
|
|
1543
2791
|
*/
|
|
1544
|
-
|
|
2792
|
+
getAll(privateKey: string): Promise<Record<string, VaultSecret>>;
|
|
1545
2793
|
/**
|
|
1546
|
-
*
|
|
2794
|
+
* List all vault secret keys (without decrypting values).
|
|
2795
|
+
*
|
|
2796
|
+
* @example
|
|
2797
|
+
* ```typescript
|
|
2798
|
+
* const keys = await ctx.noorm.vault.list()
|
|
2799
|
+
* ```
|
|
1547
2800
|
*/
|
|
1548
|
-
|
|
2801
|
+
list(): Promise<string[]>;
|
|
1549
2802
|
/**
|
|
1550
|
-
*
|
|
2803
|
+
* Delete a vault secret.
|
|
2804
|
+
*
|
|
2805
|
+
* @example
|
|
2806
|
+
* ```typescript
|
|
2807
|
+
* const [deleted, err] = await ctx.noorm.vault.delete('OLD_KEY')
|
|
2808
|
+
* ```
|
|
1551
2809
|
*/
|
|
1552
|
-
|
|
2810
|
+
delete(key: string): Promise<[
|
|
2811
|
+
boolean,
|
|
2812
|
+
Error | null
|
|
2813
|
+
]>;
|
|
1553
2814
|
/**
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
2815
|
+
* Check if a vault secret exists.
|
|
2816
|
+
*
|
|
2817
|
+
* @example
|
|
2818
|
+
* ```typescript
|
|
2819
|
+
* const exists = await ctx.noorm.vault.exists('API_KEY')
|
|
2820
|
+
* ```
|
|
1557
2821
|
*/
|
|
1558
|
-
|
|
2822
|
+
exists(key: string): Promise<boolean>;
|
|
1559
2823
|
/**
|
|
1560
|
-
*
|
|
1561
|
-
*
|
|
1562
|
-
*
|
|
2824
|
+
* Propagate vault key to all users without access.
|
|
2825
|
+
*
|
|
2826
|
+
* @example
|
|
2827
|
+
* ```typescript
|
|
2828
|
+
* const result = await ctx.noorm.vault.propagate(privateKey)
|
|
2829
|
+
* ```
|
|
1563
2830
|
*/
|
|
1564
|
-
|
|
2831
|
+
propagate(privateKey: string): Promise<VaultPropagationResult>;
|
|
1565
2832
|
/**
|
|
1566
|
-
*
|
|
1567
|
-
*
|
|
2833
|
+
* Copy vault secrets to another config's database.
|
|
2834
|
+
*
|
|
2835
|
+
* @example
|
|
2836
|
+
* ```typescript
|
|
2837
|
+
* const [result, err] = await ctx.noorm.vault.copy(destConfig, ['API_KEY'], privateKey)
|
|
2838
|
+
* ```
|
|
1568
2839
|
*/
|
|
1569
|
-
|
|
2840
|
+
copy(destConfig: Config, keys: string[] | "all", privateKey: string, options?: VaultCopyOptions): Promise<[
|
|
2841
|
+
VaultCopyResult | null,
|
|
2842
|
+
Error | null
|
|
2843
|
+
]>;
|
|
2844
|
+
}
|
|
2845
|
+
export declare class SecretsNamespace {
|
|
2846
|
+
#private;
|
|
2847
|
+
constructor(state: ContextState);
|
|
1570
2848
|
/**
|
|
1571
|
-
*
|
|
1572
|
-
* picked up by the queue and processed.
|
|
1573
|
-
*
|
|
1574
|
-
* @param data The data to add to the queue
|
|
1575
|
-
* @param priority The priority of the data
|
|
1576
|
-
*
|
|
1577
|
-
* @note If priority is provided, it will be used to determine the order of the data in the queue.
|
|
1578
|
-
* The higher the priority, the sooner the data will be processed.
|
|
2849
|
+
* Get a config-scoped secret.
|
|
1579
2850
|
*
|
|
1580
|
-
* @
|
|
2851
|
+
* @example
|
|
2852
|
+
* ```typescript
|
|
2853
|
+
* const apiKey = ctx.noorm.secrets.get('API_KEY')
|
|
2854
|
+
* ```
|
|
1581
2855
|
*/
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
off<K extends keyof QueueEvents<S, E>>(event: K, listener?: Function): void;
|
|
2856
|
+
get(key: string): string | undefined;
|
|
2857
|
+
}
|
|
2858
|
+
/**
|
|
2859
|
+
* Result of processing a SQL file.
|
|
2860
|
+
*/
|
|
2861
|
+
interface ProcessResult {
|
|
1589
2862
|
/**
|
|
1590
|
-
* The
|
|
2863
|
+
* The SQL content (rendered if template, raw if .sql).
|
|
1591
2864
|
*/
|
|
1592
|
-
|
|
2865
|
+
sql: string;
|
|
1593
2866
|
/**
|
|
1594
|
-
* Whether the
|
|
1595
|
-
* the
|
|
2867
|
+
* Whether the file was a template.
|
|
1596
2868
|
*/
|
|
1597
|
-
|
|
2869
|
+
isTemplate: boolean;
|
|
1598
2870
|
/**
|
|
1599
|
-
*
|
|
2871
|
+
* Render duration in milliseconds (only for templates).
|
|
1600
2872
|
*/
|
|
1601
|
-
|
|
2873
|
+
durationMs?: number;
|
|
2874
|
+
}
|
|
2875
|
+
export declare class TemplatesNamespace {
|
|
2876
|
+
#private;
|
|
2877
|
+
constructor(state: ContextState);
|
|
1602
2878
|
/**
|
|
1603
|
-
*
|
|
2879
|
+
* Render a template file without executing.
|
|
2880
|
+
*
|
|
2881
|
+
* @example
|
|
2882
|
+
* ```typescript
|
|
2883
|
+
* const result = await ctx.noorm.templates.render('sql/001_users.sql.tmpl')
|
|
2884
|
+
* ```
|
|
1604
2885
|
*/
|
|
1605
|
-
|
|
2886
|
+
render(filepath: string): Promise<ProcessResult>;
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Strategy for handling primary key conflicts during transfer.
|
|
2890
|
+
*
|
|
2891
|
+
* - `fail`: Abort on first conflict (default)
|
|
2892
|
+
* - `skip`: Skip conflicting rows, continue transfer
|
|
2893
|
+
* - `update`: Update existing rows with source data
|
|
2894
|
+
* - `replace`: Delete and re-insert conflicting rows
|
|
2895
|
+
*/
|
|
2896
|
+
export type ConflictStrategy = "fail" | "skip" | "update" | "replace";
|
|
2897
|
+
/**
|
|
2898
|
+
* Options for data transfer operations.
|
|
2899
|
+
*
|
|
2900
|
+
* @example
|
|
2901
|
+
* ```typescript
|
|
2902
|
+
* const options: TransferOptions = {
|
|
2903
|
+
* tables: ['users', 'posts'],
|
|
2904
|
+
* onConflict: 'skip',
|
|
2905
|
+
* batchSize: 5000,
|
|
2906
|
+
* truncateFirst: false,
|
|
2907
|
+
* };
|
|
2908
|
+
* ```
|
|
2909
|
+
*/
|
|
2910
|
+
export interface TransferOptions {
|
|
2911
|
+
/** Tables to transfer. Empty = all user tables. */
|
|
2912
|
+
tables?: string[];
|
|
2913
|
+
/** How to handle primary key conflicts. Default: 'fail' */
|
|
2914
|
+
onConflict?: ConflictStrategy;
|
|
2915
|
+
/** Rows per batch for cross-server transfers. Default: 1000 */
|
|
2916
|
+
batchSize?: number;
|
|
2917
|
+
/** Disable foreign key checks during transfer. Default: true */
|
|
2918
|
+
disableForeignKeys?: boolean;
|
|
2919
|
+
/** Preserve identity/auto-increment values. Default: true */
|
|
2920
|
+
preserveIdentity?: boolean;
|
|
2921
|
+
/** Truncate destination tables before transfer. Default: false */
|
|
2922
|
+
truncateFirst?: boolean;
|
|
2923
|
+
/** Validate only, don't execute. Default: false */
|
|
2924
|
+
dryRun?: boolean;
|
|
2925
|
+
/** Export to .dt file instead of DB insert. */
|
|
2926
|
+
exportPath?: string;
|
|
2927
|
+
/** Passphrase for .dtzx export encryption. */
|
|
2928
|
+
passphrase?: string;
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* Plan for a single table transfer.
|
|
2932
|
+
*/
|
|
2933
|
+
export interface TransferTablePlan {
|
|
2934
|
+
/** Table name */
|
|
2935
|
+
name: string;
|
|
2936
|
+
/** Table schema (if applicable) */
|
|
2937
|
+
schema?: string;
|
|
2938
|
+
/** Estimated row count */
|
|
2939
|
+
rowCount: number;
|
|
2940
|
+
/** Whether table has identity/auto-increment column */
|
|
2941
|
+
hasIdentity: boolean;
|
|
2942
|
+
/** Identity column name if present */
|
|
2943
|
+
identityColumn?: string;
|
|
2944
|
+
/** Primary key columns */
|
|
2945
|
+
primaryKey: string[];
|
|
2946
|
+
/** All column names */
|
|
2947
|
+
columns: string[];
|
|
2948
|
+
/** Tables this table depends on (FK references) */
|
|
2949
|
+
dependsOn: string[];
|
|
2950
|
+
/** Column type definitions for cross-dialect transfers. */
|
|
2951
|
+
columnTypes?: DtColumn[];
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Complete transfer plan.
|
|
2955
|
+
*
|
|
2956
|
+
* Contains ordered list of tables and transfer metadata.
|
|
2957
|
+
*/
|
|
2958
|
+
export interface TransferPlan {
|
|
2959
|
+
/** Tables in dependency order (parents before children) */
|
|
2960
|
+
tables: TransferTablePlan[];
|
|
2961
|
+
/** Whether source and destination are on same server */
|
|
2962
|
+
sameServer: boolean;
|
|
2963
|
+
/** Total estimated rows across all tables */
|
|
2964
|
+
estimatedRows: number;
|
|
2965
|
+
/** Warnings about potential issues */
|
|
2966
|
+
warnings: string[];
|
|
2967
|
+
/** Whether this is a cross-dialect transfer. */
|
|
2968
|
+
crossDialect: boolean;
|
|
2969
|
+
/** Source database dialect. */
|
|
2970
|
+
sourceDialect: Dialect;
|
|
2971
|
+
/** Destination database dialect. */
|
|
2972
|
+
destinationDialect: Dialect;
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* Result for a single table transfer.
|
|
2976
|
+
*/
|
|
2977
|
+
export interface TransferTableResult {
|
|
2978
|
+
/** Table name */
|
|
2979
|
+
table: string;
|
|
2980
|
+
/** Transfer status */
|
|
2981
|
+
status: "success" | "skipped" | "failed";
|
|
2982
|
+
/** Rows successfully transferred */
|
|
2983
|
+
rowsTransferred: number;
|
|
2984
|
+
/** Rows skipped due to conflicts */
|
|
2985
|
+
rowsSkipped: number;
|
|
2986
|
+
/** Duration in milliseconds */
|
|
2987
|
+
durationMs: number;
|
|
2988
|
+
/** Error message if failed */
|
|
2989
|
+
error?: string;
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Complete transfer result.
|
|
2993
|
+
*/
|
|
2994
|
+
export interface TransferResult {
|
|
2995
|
+
/** Overall status */
|
|
2996
|
+
status: "success" | "partial" | "failed";
|
|
2997
|
+
/** Results per table */
|
|
2998
|
+
tables: TransferTableResult[];
|
|
2999
|
+
/** Total rows transferred */
|
|
3000
|
+
totalRows: number;
|
|
3001
|
+
/** Total duration in milliseconds */
|
|
3002
|
+
durationMs: number;
|
|
3003
|
+
}
|
|
3004
|
+
export declare class TransferNamespace {
|
|
3005
|
+
#private;
|
|
3006
|
+
constructor(state: ContextState);
|
|
1606
3007
|
/**
|
|
1607
|
-
*
|
|
3008
|
+
* Transfer data to a destination database.
|
|
3009
|
+
*
|
|
3010
|
+
* @example
|
|
3011
|
+
* ```typescript
|
|
3012
|
+
* const [result, err] = await ctx.noorm.transfer.to(destConfig, {
|
|
3013
|
+
* tables: ['users', 'posts'],
|
|
3014
|
+
* onConflict: 'skip',
|
|
3015
|
+
* })
|
|
3016
|
+
* ```
|
|
1608
3017
|
*/
|
|
1609
|
-
|
|
3018
|
+
to(destConfig: Config, options?: TransferOptions): Promise<[
|
|
3019
|
+
TransferResult | null,
|
|
3020
|
+
Error | null
|
|
3021
|
+
]>;
|
|
1610
3022
|
/**
|
|
1611
|
-
*
|
|
3023
|
+
* Generate a transfer plan without executing.
|
|
3024
|
+
*
|
|
3025
|
+
* @example
|
|
3026
|
+
* ```typescript
|
|
3027
|
+
* const [plan, err] = await ctx.noorm.transfer.plan(destConfig)
|
|
3028
|
+
* ```
|
|
1612
3029
|
*/
|
|
1613
|
-
|
|
3030
|
+
plan(destConfig: Config, options?: TransferOptions): Promise<[
|
|
3031
|
+
TransferPlan | null,
|
|
3032
|
+
Error | null
|
|
3033
|
+
]>;
|
|
3034
|
+
}
|
|
3035
|
+
export declare class DtNamespace {
|
|
3036
|
+
#private;
|
|
3037
|
+
constructor(state: ContextState);
|
|
1614
3038
|
/**
|
|
1615
|
-
*
|
|
3039
|
+
* Export a table to a .dt file.
|
|
3040
|
+
*
|
|
3041
|
+
* @example
|
|
3042
|
+
* ```typescript
|
|
3043
|
+
* const [result, err] = await ctx.noorm.dt.exportTable('users', './exports/users.dtz')
|
|
3044
|
+
* ```
|
|
1616
3045
|
*/
|
|
1617
|
-
|
|
3046
|
+
exportTable(tableName: string, filepath: string, options?: ExportOptions): Promise<[
|
|
3047
|
+
{
|
|
3048
|
+
rowsWritten: number;
|
|
3049
|
+
bytesWritten: number;
|
|
3050
|
+
} | null,
|
|
3051
|
+
Error | null
|
|
3052
|
+
]>;
|
|
1618
3053
|
/**
|
|
1619
|
-
*
|
|
3054
|
+
* Import a .dt file into the connected database.
|
|
3055
|
+
*
|
|
3056
|
+
* @example
|
|
3057
|
+
* ```typescript
|
|
3058
|
+
* const [result, err] = await ctx.noorm.dt.importFile('./exports/users.dtz', {
|
|
3059
|
+
* onConflict: 'skip',
|
|
3060
|
+
* })
|
|
3061
|
+
* ```
|
|
1620
3062
|
*/
|
|
1621
|
-
|
|
3063
|
+
importFile(filepath: string, options?: ImportOptions): Promise<[
|
|
3064
|
+
{
|
|
3065
|
+
rowsImported: number;
|
|
3066
|
+
rowsSkipped: number;
|
|
3067
|
+
} | null,
|
|
3068
|
+
Error | null
|
|
3069
|
+
]>;
|
|
3070
|
+
}
|
|
3071
|
+
export declare class UtilsNamespace {
|
|
3072
|
+
#private;
|
|
3073
|
+
constructor(state: ContextState);
|
|
1622
3074
|
/**
|
|
1623
|
-
*
|
|
3075
|
+
* Compute SHA-256 checksum for a file.
|
|
3076
|
+
*
|
|
3077
|
+
* @example
|
|
3078
|
+
* ```typescript
|
|
3079
|
+
* const checksum = await ctx.noorm.utils.checksum('sql/001_users.sql')
|
|
3080
|
+
* ```
|
|
1624
3081
|
*/
|
|
1625
|
-
|
|
3082
|
+
checksum(filepath: string): Promise<string>;
|
|
1626
3083
|
/**
|
|
1627
|
-
*
|
|
3084
|
+
* Tests if the connection can be established.
|
|
3085
|
+
*
|
|
3086
|
+
* @example
|
|
3087
|
+
* ```typescript
|
|
3088
|
+
* const result = await ctx.noorm.utils.testConnection()
|
|
3089
|
+
* ```
|
|
1628
3090
|
*/
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
success: number;
|
|
1634
|
-
error: number;
|
|
1635
|
-
rejected: number;
|
|
1636
|
-
};
|
|
1637
|
-
get snapshot(): {
|
|
1638
|
-
name: string;
|
|
1639
|
-
state: QueueState;
|
|
1640
|
-
pending: number;
|
|
1641
|
-
stats: {
|
|
1642
|
-
processed: number;
|
|
1643
|
-
processing: number;
|
|
1644
|
-
avgProcessingTime: number;
|
|
1645
|
-
success: number;
|
|
1646
|
-
error: number;
|
|
1647
|
-
rejected: number;
|
|
1648
|
-
};
|
|
1649
|
-
rateLimiter: {
|
|
1650
|
-
currentTokens: number;
|
|
1651
|
-
capacity: number;
|
|
1652
|
-
refillIntervalMs: number;
|
|
1653
|
-
totalRequests: number;
|
|
1654
|
-
rejectedRequests: number;
|
|
1655
|
-
successfulRequests: number;
|
|
1656
|
-
rejectionRate: number;
|
|
1657
|
-
totalWaitTime: number;
|
|
1658
|
-
waitCount: number;
|
|
1659
|
-
averageWaitTime: number;
|
|
1660
|
-
uptime: number;
|
|
1661
|
-
createdAt: number;
|
|
1662
|
-
};
|
|
1663
|
-
activeRunners: number;
|
|
1664
|
-
runningNodes: Set<`${number}-${number}`>;
|
|
1665
|
-
isIdle: boolean;
|
|
1666
|
-
isWaiting: boolean;
|
|
1667
|
-
isRunning: boolean;
|
|
1668
|
-
isPaused: boolean;
|
|
1669
|
-
isStopped: boolean;
|
|
1670
|
-
isDraining: boolean;
|
|
1671
|
-
isEmpty: boolean;
|
|
1672
|
-
};
|
|
3091
|
+
testConnection(): Promise<{
|
|
3092
|
+
ok: boolean;
|
|
3093
|
+
error?: string;
|
|
3094
|
+
}>;
|
|
1673
3095
|
}
|
|
1674
3096
|
/**
|
|
1675
3097
|
* Shutdown phases in order of execution.
|
|
@@ -1689,6 +3111,288 @@ export type ShutdownReason = "signal" | "user" | "error" | "programmatic";
|
|
|
1689
3111
|
* Application mode.
|
|
1690
3112
|
*/
|
|
1691
3113
|
export type AppMode = "tui" | "headless";
|
|
3114
|
+
/**
|
|
3115
|
+
* Type definitions for auto-update feature.
|
|
3116
|
+
*
|
|
3117
|
+
* Includes global settings structure and update check/result types.
|
|
3118
|
+
*/
|
|
3119
|
+
/**
|
|
3120
|
+
* Dismissable alert preference.
|
|
3121
|
+
*
|
|
3122
|
+
* Controls how alerts are handled after user makes a choice:
|
|
3123
|
+
* - 'ask': Show the alert and ask user each time (default)
|
|
3124
|
+
* - 'always': Always perform the action without asking
|
|
3125
|
+
* - 'never': Never perform the action, auto-deny
|
|
3126
|
+
*/
|
|
3127
|
+
export type DismissablePreference = "ask" | "always" | "never";
|
|
3128
|
+
/**
|
|
3129
|
+
* Global settings stored in ~/.noorm/settings.yml
|
|
3130
|
+
*
|
|
3131
|
+
* These are user-level settings, separate from project settings.
|
|
3132
|
+
* Used for preferences that apply across all projects.
|
|
3133
|
+
*/
|
|
3134
|
+
export interface GlobalSettings {
|
|
3135
|
+
/** Check for updates on TUI launch (default: true) */
|
|
3136
|
+
checkUpdates: boolean;
|
|
3137
|
+
/** Auto-install updates without prompting (default: false) */
|
|
3138
|
+
autoUpdate: boolean;
|
|
3139
|
+
/** Last check timestamp (ISO string) */
|
|
3140
|
+
lastCheck?: string;
|
|
3141
|
+
/** Cached latest version from last check */
|
|
3142
|
+
cachedVersion?: string;
|
|
3143
|
+
/**
|
|
3144
|
+
* Dismissable alert preferences.
|
|
3145
|
+
*
|
|
3146
|
+
* Stores user decisions for alerts that can be permanently dismissed.
|
|
3147
|
+
* Keys are alert identifiers (e.g., 'majorVersionUpdate').
|
|
3148
|
+
*/
|
|
3149
|
+
dismissable?: Record<string, DismissablePreference>;
|
|
3150
|
+
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Events emitted by the update module.
|
|
3153
|
+
*
|
|
3154
|
+
* Used to integrate with the observer event system.
|
|
3155
|
+
*/
|
|
3156
|
+
export interface UpdateEvents {
|
|
3157
|
+
"update:checking": Record<string, never>;
|
|
3158
|
+
"update:available": {
|
|
3159
|
+
currentVersion: string;
|
|
3160
|
+
latestVersion: string;
|
|
3161
|
+
};
|
|
3162
|
+
"update:major-available": {
|
|
3163
|
+
currentVersion: string;
|
|
3164
|
+
latestVersion: string;
|
|
3165
|
+
};
|
|
3166
|
+
"update:not-available": {
|
|
3167
|
+
currentVersion: string;
|
|
3168
|
+
};
|
|
3169
|
+
"update:check-failed": {
|
|
3170
|
+
error: string;
|
|
3171
|
+
};
|
|
3172
|
+
"update:installing": {
|
|
3173
|
+
version: string;
|
|
3174
|
+
};
|
|
3175
|
+
"update:complete": {
|
|
3176
|
+
previousVersion: string;
|
|
3177
|
+
newVersion: string;
|
|
3178
|
+
};
|
|
3179
|
+
"update:failed": {
|
|
3180
|
+
version: string;
|
|
3181
|
+
error: string;
|
|
3182
|
+
};
|
|
3183
|
+
"update:skipped": {
|
|
3184
|
+
version: string;
|
|
3185
|
+
reason: "user-denied" | "user-deferred";
|
|
3186
|
+
};
|
|
3187
|
+
"global-settings:loaded": {
|
|
3188
|
+
settings: GlobalSettings;
|
|
3189
|
+
};
|
|
3190
|
+
"global-settings:updated": {
|
|
3191
|
+
key: string;
|
|
3192
|
+
value: unknown;
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Transfer event types for observer integration.
|
|
3197
|
+
*
|
|
3198
|
+
* Events emitted during data transfer operations for CLI progress display.
|
|
3199
|
+
*/
|
|
3200
|
+
/**
|
|
3201
|
+
* Events emitted by the transfer module.
|
|
3202
|
+
*
|
|
3203
|
+
* Subscribe to these events to track transfer progress in the CLI.
|
|
3204
|
+
*/
|
|
3205
|
+
export interface TransferEvents {
|
|
3206
|
+
/** Emitted when transfer planning starts */
|
|
3207
|
+
"transfer:planning": {
|
|
3208
|
+
source: string;
|
|
3209
|
+
destination: string;
|
|
3210
|
+
};
|
|
3211
|
+
/** Emitted when transfer plan is ready */
|
|
3212
|
+
"transfer:plan:ready": {
|
|
3213
|
+
sameServer: boolean;
|
|
3214
|
+
tableCount: number;
|
|
3215
|
+
estimatedRows: number;
|
|
3216
|
+
warnings: string[];
|
|
3217
|
+
};
|
|
3218
|
+
/** Emitted when transfer execution starts */
|
|
3219
|
+
"transfer:starting": {
|
|
3220
|
+
tableCount: number;
|
|
3221
|
+
sameServer: boolean;
|
|
3222
|
+
};
|
|
3223
|
+
/** Emitted before transferring each table */
|
|
3224
|
+
"transfer:table:before": {
|
|
3225
|
+
table: string;
|
|
3226
|
+
index: number;
|
|
3227
|
+
total: number;
|
|
3228
|
+
rowCount: number;
|
|
3229
|
+
};
|
|
3230
|
+
/** Emitted during table transfer with progress */
|
|
3231
|
+
"transfer:table:progress": {
|
|
3232
|
+
table: string;
|
|
3233
|
+
rowsTransferred: number;
|
|
3234
|
+
rowsTotal: number;
|
|
3235
|
+
rowsSkipped: number;
|
|
3236
|
+
};
|
|
3237
|
+
/** Emitted after transferring each table */
|
|
3238
|
+
"transfer:table:after": {
|
|
3239
|
+
table: string;
|
|
3240
|
+
status: "success" | "skipped" | "failed";
|
|
3241
|
+
rowsTransferred: number;
|
|
3242
|
+
rowsSkipped: number;
|
|
3243
|
+
durationMs: number;
|
|
3244
|
+
error?: string;
|
|
3245
|
+
};
|
|
3246
|
+
/** Emitted when transfer completes */
|
|
3247
|
+
"transfer:complete": {
|
|
3248
|
+
status: "success" | "partial" | "failed";
|
|
3249
|
+
totalRows: number;
|
|
3250
|
+
tableCount: number;
|
|
3251
|
+
durationMs: number;
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
/**
|
|
3255
|
+
* Events emitted by the dt module.
|
|
3256
|
+
*
|
|
3257
|
+
* Subscribe to these events to track .dt operation progress in the CLI.
|
|
3258
|
+
*/
|
|
3259
|
+
export interface DtEvents {
|
|
3260
|
+
/** Export begins for a table. */
|
|
3261
|
+
"dt:export:start": {
|
|
3262
|
+
filepath: string;
|
|
3263
|
+
table: string;
|
|
3264
|
+
columnCount: number;
|
|
3265
|
+
};
|
|
3266
|
+
/** After each batch flush during export. */
|
|
3267
|
+
"dt:export:progress": {
|
|
3268
|
+
filepath: string;
|
|
3269
|
+
table: string;
|
|
3270
|
+
rowsWritten: number;
|
|
3271
|
+
bytesWritten: number;
|
|
3272
|
+
};
|
|
3273
|
+
/** Export finished for a table. */
|
|
3274
|
+
"dt:export:complete": {
|
|
3275
|
+
filepath: string;
|
|
3276
|
+
table: string;
|
|
3277
|
+
rowsWritten: number;
|
|
3278
|
+
bytesWritten: number;
|
|
3279
|
+
durationMs: number;
|
|
3280
|
+
};
|
|
3281
|
+
/** Import begins for a file. */
|
|
3282
|
+
"dt:import:start": {
|
|
3283
|
+
filepath: string;
|
|
3284
|
+
sourceDialect: string;
|
|
3285
|
+
sourceVersion: string;
|
|
3286
|
+
table: string;
|
|
3287
|
+
};
|
|
3288
|
+
/** Schema parsed and validated during import. */
|
|
3289
|
+
"dt:import:schema": {
|
|
3290
|
+
filepath: string;
|
|
3291
|
+
table: string;
|
|
3292
|
+
columns: number;
|
|
3293
|
+
validation: SchemaValidationResult;
|
|
3294
|
+
};
|
|
3295
|
+
/** After each batch insert during import. */
|
|
3296
|
+
"dt:import:progress": {
|
|
3297
|
+
filepath: string;
|
|
3298
|
+
table: string;
|
|
3299
|
+
rowsImported: number;
|
|
3300
|
+
rowsSkipped: number;
|
|
3301
|
+
};
|
|
3302
|
+
/** Import finished for a file. */
|
|
3303
|
+
"dt:import:complete": {
|
|
3304
|
+
filepath: string;
|
|
3305
|
+
table: string;
|
|
3306
|
+
rowsImported: number;
|
|
3307
|
+
rowsSkipped: number;
|
|
3308
|
+
durationMs: number;
|
|
3309
|
+
};
|
|
3310
|
+
/** Cross-dialect stream begins. */
|
|
3311
|
+
"dt:stream:start": {
|
|
3312
|
+
table: string;
|
|
3313
|
+
sourceDialect: string;
|
|
3314
|
+
targetDialect: string;
|
|
3315
|
+
};
|
|
3316
|
+
/** After each batch conversion during streaming. */
|
|
3317
|
+
"dt:stream:progress": {
|
|
3318
|
+
table: string;
|
|
3319
|
+
rowsConverted: number;
|
|
3320
|
+
};
|
|
3321
|
+
/** Cross-dialect stream finished. */
|
|
3322
|
+
"dt:stream:complete": {
|
|
3323
|
+
table: string;
|
|
3324
|
+
rowsConverted: number;
|
|
3325
|
+
durationMs: number;
|
|
3326
|
+
};
|
|
3327
|
+
/** Schema validation completed. */
|
|
3328
|
+
"dt:validate:result": {
|
|
3329
|
+
table: string;
|
|
3330
|
+
valid: boolean;
|
|
3331
|
+
errors: string[];
|
|
3332
|
+
warnings: string[];
|
|
3333
|
+
};
|
|
3334
|
+
/** A batch of rows arrived from the Connection Worker. */
|
|
3335
|
+
"dt:export:loaded": {
|
|
3336
|
+
table: string;
|
|
3337
|
+
loaded: number;
|
|
3338
|
+
totalRows: number;
|
|
3339
|
+
};
|
|
3340
|
+
/** A compute worker finished serializing a row. */
|
|
3341
|
+
"dt:export:processed": {
|
|
3342
|
+
table: string;
|
|
3343
|
+
processed: number;
|
|
3344
|
+
totalRows: number;
|
|
3345
|
+
};
|
|
3346
|
+
/** Order buffer flushed consecutive rows to DtWriter. */
|
|
3347
|
+
"dt:export:saved": {
|
|
3348
|
+
table: string;
|
|
3349
|
+
saved: number;
|
|
3350
|
+
totalRows: number;
|
|
3351
|
+
};
|
|
3352
|
+
/** A batch of lines read from file by DtReader. */
|
|
3353
|
+
"dt:import:loaded": {
|
|
3354
|
+
table: string;
|
|
3355
|
+
loaded: number;
|
|
3356
|
+
totalRows: number;
|
|
3357
|
+
};
|
|
3358
|
+
/** A compute worker finished deserializing a row. */
|
|
3359
|
+
"dt:import:processed": {
|
|
3360
|
+
table: string;
|
|
3361
|
+
processed: number;
|
|
3362
|
+
totalRows: number;
|
|
3363
|
+
};
|
|
3364
|
+
/** Deserialized rows inserted into the database. */
|
|
3365
|
+
"dt:import:saved": {
|
|
3366
|
+
table: string;
|
|
3367
|
+
saved: number;
|
|
3368
|
+
totalRows: number;
|
|
3369
|
+
};
|
|
3370
|
+
/** Modify operation begins. */
|
|
3371
|
+
"dt:modify:start": {
|
|
3372
|
+
inputPath: string;
|
|
3373
|
+
outputPath: string;
|
|
3374
|
+
recipeLength: number;
|
|
3375
|
+
};
|
|
3376
|
+
/** After each row processed during modify. */
|
|
3377
|
+
"dt:modify:progress": {
|
|
3378
|
+
rowsRead: number;
|
|
3379
|
+
rowsWritten: number;
|
|
3380
|
+
rowsFiltered: number;
|
|
3381
|
+
};
|
|
3382
|
+
/** Modify operation finished. */
|
|
3383
|
+
"dt:modify:complete": {
|
|
3384
|
+
result: {
|
|
3385
|
+
rowsRead: number;
|
|
3386
|
+
rowsWritten: number;
|
|
3387
|
+
rowsFiltered: number;
|
|
3388
|
+
columnsDropped: number;
|
|
3389
|
+
columnsAdded: number;
|
|
3390
|
+
columnsRenamed: number;
|
|
3391
|
+
outputPath: string;
|
|
3392
|
+
durationMs: number;
|
|
3393
|
+
};
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
1692
3396
|
/**
|
|
1693
3397
|
* All events emitted by noorm core modules.
|
|
1694
3398
|
*
|
|
@@ -1706,9 +3410,12 @@ export type AppMode = "tui" | "headless";
|
|
|
1706
3410
|
* - `identity:*` - Identity resolution
|
|
1707
3411
|
* - `connection:*` - Database connections
|
|
1708
3412
|
* - `settings:*` - Settings lifecycle and mutations
|
|
3413
|
+
* - `vault:*` - Vault operations
|
|
3414
|
+
* - `transfer:*` - Data transfer operations
|
|
3415
|
+
* - `dt:*` - .dt format export/import/stream operations
|
|
1709
3416
|
* - `error` - Catch-all errors
|
|
1710
3417
|
*/
|
|
1711
|
-
export interface NoormEvents extends SettingsEvents {
|
|
3418
|
+
export interface NoormEvents extends SettingsEvents, UpdateEvents, VaultEvents, TransferEvents, DtEvents {
|
|
1712
3419
|
"file:before": {
|
|
1713
3420
|
filepath: string;
|
|
1714
3421
|
checksum: string;
|
|
@@ -1726,7 +3433,9 @@ export interface NoormEvents extends SettingsEvents {
|
|
|
1726
3433
|
};
|
|
1727
3434
|
"file:dry-run": {
|
|
1728
3435
|
filepath: string;
|
|
1729
|
-
|
|
3436
|
+
status: "success" | "failed";
|
|
3437
|
+
outputPath?: string;
|
|
3438
|
+
error?: string;
|
|
1730
3439
|
};
|
|
1731
3440
|
"change:created": {
|
|
1732
3441
|
name: string;
|
|
@@ -1763,6 +3472,7 @@ export interface NoormEvents extends SettingsEvents {
|
|
|
1763
3472
|
filesSkipped: number;
|
|
1764
3473
|
filesFailed: number;
|
|
1765
3474
|
durationMs: number;
|
|
3475
|
+
error?: string;
|
|
1766
3476
|
};
|
|
1767
3477
|
"run:file": {
|
|
1768
3478
|
filepath: string;
|
|
@@ -1893,6 +3603,7 @@ export interface NoormEvents extends SettingsEvents {
|
|
|
1893
3603
|
registered: boolean;
|
|
1894
3604
|
knownUsersCount: number;
|
|
1895
3605
|
};
|
|
3606
|
+
"identity:not-found": void;
|
|
1896
3607
|
"connection:open": {
|
|
1897
3608
|
configName: string;
|
|
1898
3609
|
dialect: string;
|
|
@@ -1944,66 +3655,208 @@ export interface NoormEvents extends SettingsEvents {
|
|
|
1944
3655
|
};
|
|
1945
3656
|
}
|
|
1946
3657
|
export type NoormEventNames = Events<NoormEvents>;
|
|
3658
|
+
/**
|
|
3659
|
+
* Noorm-specific operations accessed via ctx.noorm.
|
|
3660
|
+
*
|
|
3661
|
+
* Domain-aligned sub-namespaces mirror the TUI home screen:
|
|
3662
|
+
* changes, run, db, lock, vault, secrets, templates, transfer, dt, utils.
|
|
3663
|
+
*
|
|
3664
|
+
* @example
|
|
3665
|
+
* ```typescript
|
|
3666
|
+
* const ctx = await createContext({ config: 'dev' })
|
|
3667
|
+
* await ctx.connect()
|
|
3668
|
+
*
|
|
3669
|
+
* await ctx.noorm.run.build()
|
|
3670
|
+
* await ctx.noorm.changes.ff()
|
|
3671
|
+
* const tables = await ctx.noorm.db.listTables()
|
|
3672
|
+
* ```
|
|
3673
|
+
*/
|
|
3674
|
+
export declare class NoormOps {
|
|
3675
|
+
#private;
|
|
3676
|
+
constructor(state: ContextState);
|
|
3677
|
+
get config(): Config;
|
|
3678
|
+
get settings(): Settings;
|
|
3679
|
+
get identity(): Identity;
|
|
3680
|
+
get observer(): ObserverEngine<NoormEvents>;
|
|
3681
|
+
get changes(): ChangesNamespace;
|
|
3682
|
+
get run(): RunNamespace;
|
|
3683
|
+
get db(): DbNamespace;
|
|
3684
|
+
get lock(): LockNamespace;
|
|
3685
|
+
get vault(): VaultNamespace;
|
|
3686
|
+
get secrets(): SecretsNamespace;
|
|
3687
|
+
get templates(): TemplatesNamespace;
|
|
3688
|
+
get transfer(): TransferNamespace;
|
|
3689
|
+
get dt(): DtNamespace;
|
|
3690
|
+
get utils(): UtilsNamespace;
|
|
3691
|
+
}
|
|
3692
|
+
/**
|
|
3693
|
+
* Scoped query interface bound to a dedicated impersonated connection.
|
|
3694
|
+
*
|
|
3695
|
+
* All queries route through a single pool connection running under
|
|
3696
|
+
* the impersonated principal. Mirrors Context's query surface without
|
|
3697
|
+
* lifecycle or noorm ops.
|
|
3698
|
+
*/
|
|
3699
|
+
export interface ImpersonatedScope<DB = unknown, Procs = object, Funcs = object> {
|
|
3700
|
+
kysely: Kysely<DB>;
|
|
3701
|
+
proc: <T = unknown, N extends keyof Procs & string = keyof Procs & string>(name: N, ...args: Procs[N] extends void ? [
|
|
3702
|
+
] : [
|
|
3703
|
+
params: Procs[N]
|
|
3704
|
+
]) => Promise<T[]>;
|
|
3705
|
+
func: <T = unknown, N extends keyof Funcs & string = keyof Funcs & string>(name: N, ...args: Funcs[N] extends void ? [
|
|
3706
|
+
column: string
|
|
3707
|
+
] : [
|
|
3708
|
+
params: Funcs[N],
|
|
3709
|
+
column: string
|
|
3710
|
+
]) => Promise<T>;
|
|
3711
|
+
transaction: <T>(fn: (trx: Transaction<DB>) => Promise<T>) => Promise<T>;
|
|
3712
|
+
revert: () => Promise<void>;
|
|
3713
|
+
}
|
|
3714
|
+
/**
|
|
3715
|
+
* Thrown when impersonation fails.
|
|
3716
|
+
*
|
|
3717
|
+
* Covers unsupported dialects and invalid usernames.
|
|
3718
|
+
*/
|
|
3719
|
+
export declare class ImpersonationError extends Error {
|
|
3720
|
+
constructor(message: string);
|
|
3721
|
+
}
|
|
1947
3722
|
/**
|
|
1948
3723
|
* SDK Context implementation.
|
|
1949
3724
|
*
|
|
1950
|
-
* Provides programmatic access to
|
|
3725
|
+
* Provides SQL-focused programmatic access to the database.
|
|
3726
|
+
* Noorm management operations are accessible via ctx.noorm.
|
|
1951
3727
|
*
|
|
1952
3728
|
* @example
|
|
1953
3729
|
* ```typescript
|
|
1954
3730
|
* const ctx = await createContext({ config: 'dev' })
|
|
1955
3731
|
* await ctx.connect()
|
|
1956
3732
|
*
|
|
1957
|
-
* //
|
|
1958
|
-
* const users = await ctx.
|
|
3733
|
+
* // Top-level — SQL focused
|
|
3734
|
+
* const users = await ctx.kysely
|
|
3735
|
+
* .selectFrom('users')
|
|
3736
|
+
* .selectAll()
|
|
3737
|
+
* .execute()
|
|
3738
|
+
*
|
|
3739
|
+
* // Noorm operations — under namespace
|
|
3740
|
+
* await ctx.noorm.run.build()
|
|
3741
|
+
* await ctx.noorm.changes.ff()
|
|
1959
3742
|
*
|
|
1960
|
-
* // Clean disconnect
|
|
1961
3743
|
* await ctx.disconnect()
|
|
1962
3744
|
* ```
|
|
1963
3745
|
*/
|
|
1964
|
-
export declare class Context<DB = unknown> {
|
|
3746
|
+
export declare class Context<DB = unknown, Procs = object, Funcs = object> {
|
|
1965
3747
|
#private;
|
|
1966
3748
|
constructor(config: Config, settings: Settings, identity: Identity, options: CreateContextOptions, projectRoot: string);
|
|
1967
|
-
get config(): Config;
|
|
1968
|
-
get settings(): Settings;
|
|
1969
|
-
get identity(): Identity;
|
|
1970
3749
|
get dialect(): Dialect;
|
|
1971
3750
|
get connected(): boolean;
|
|
1972
|
-
get observer(): ObserverEngine<NoormEvents>;
|
|
1973
3751
|
get kysely(): Kysely<DB>;
|
|
3752
|
+
/**
|
|
3753
|
+
* Noorm management operations.
|
|
3754
|
+
*
|
|
3755
|
+
* Lazily instantiated on first access. Returns the same instance
|
|
3756
|
+
* on repeated access (singleton per Context).
|
|
3757
|
+
*
|
|
3758
|
+
* @example
|
|
3759
|
+
* ```typescript
|
|
3760
|
+
* await ctx.noorm.run.build()
|
|
3761
|
+
* await ctx.noorm.changes.ff()
|
|
3762
|
+
* const tables = await ctx.noorm.db.listTables()
|
|
3763
|
+
* ```
|
|
3764
|
+
*/
|
|
3765
|
+
get noorm(): NoormOps;
|
|
1974
3766
|
connect(): Promise<void>;
|
|
1975
3767
|
disconnect(): Promise<void>;
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
3768
|
+
/**
|
|
3769
|
+
* Execute operations within a database transaction.
|
|
3770
|
+
*
|
|
3771
|
+
* The callback receives a full Kysely Transaction instance with
|
|
3772
|
+
* query builder, `sql` template literal, and all Kysely features.
|
|
3773
|
+
*
|
|
3774
|
+
* @example
|
|
3775
|
+
* ```typescript
|
|
3776
|
+
* await ctx.transaction(async (trx) => {
|
|
3777
|
+
* await trx
|
|
3778
|
+
* .updateTable('accounts')
|
|
3779
|
+
* .set({ balance: sql`balance - ${amount}` })
|
|
3780
|
+
* .where('id', '=', fromId)
|
|
3781
|
+
* .execute();
|
|
3782
|
+
* await trx
|
|
3783
|
+
* .updateTable('accounts')
|
|
3784
|
+
* .set({ balance: sql`balance + ${amount}` })
|
|
3785
|
+
* .where('id', '=', toId)
|
|
3786
|
+
* .execute();
|
|
3787
|
+
* });
|
|
3788
|
+
* ```
|
|
3789
|
+
*/
|
|
3790
|
+
transaction<T>(fn: (trx: Transaction<DB>) => Promise<T>): Promise<T>;
|
|
3791
|
+
/**
|
|
3792
|
+
* Call a stored procedure and return the result set.
|
|
3793
|
+
*
|
|
3794
|
+
* Generates dialect-specific SQL: EXEC (MSSQL), CALL (PG/MySQL).
|
|
3795
|
+
* Named params use dialect-appropriate syntax; MySQL falls back
|
|
3796
|
+
* to positional. SQLite throws — no procedure support.
|
|
3797
|
+
*
|
|
3798
|
+
* @example
|
|
3799
|
+
* ```typescript
|
|
3800
|
+
* // Named params
|
|
3801
|
+
* const users = await ctx.proc<User>('get_users', { department_id: 1 });
|
|
3802
|
+
*
|
|
3803
|
+
* // Positional params
|
|
3804
|
+
* await ctx.proc('simple_proc', [42, 'hello']);
|
|
3805
|
+
*
|
|
3806
|
+
* // No params
|
|
3807
|
+
* await ctx.proc('refresh_cache');
|
|
3808
|
+
* ```
|
|
3809
|
+
*/
|
|
3810
|
+
proc<T = unknown, N extends keyof Procs & string = keyof Procs & string>(name: N, ...args: Procs[N] extends void ? [
|
|
3811
|
+
] : [
|
|
3812
|
+
params: Procs[N]
|
|
3813
|
+
]): Promise<T[]>;
|
|
3814
|
+
/**
|
|
3815
|
+
* Call a database function and return the scalar result.
|
|
3816
|
+
*
|
|
3817
|
+
* Generates SELECT name(...) AS column. Named params only on PG;
|
|
3818
|
+
* other dialects fall back to positional. SQLite throws.
|
|
3819
|
+
*
|
|
3820
|
+
* @example
|
|
3821
|
+
* ```typescript
|
|
3822
|
+
* // Named params + column alias
|
|
3823
|
+
* const result = await ctx.func<{ total: number }>('calc_total', { order_id: 42 }, 'total');
|
|
3824
|
+
*
|
|
3825
|
+
* // Positional params + column alias
|
|
3826
|
+
* const sum = await ctx.func<{ result: number }>('add_numbers', [1, 2], 'result');
|
|
3827
|
+
*
|
|
3828
|
+
* // No params — just column alias
|
|
3829
|
+
* const ver = await ctx.func<{ v: string }>('get_version', 'v');
|
|
3830
|
+
* ```
|
|
3831
|
+
*/
|
|
3832
|
+
func<T = unknown, N extends keyof Funcs & string = keyof Funcs & string>(name: N, ...args: Funcs[N] extends void ? [
|
|
3833
|
+
column: string
|
|
3834
|
+
] : [
|
|
3835
|
+
params: Funcs[N],
|
|
3836
|
+
column: string
|
|
3837
|
+
]): Promise<T>;
|
|
3838
|
+
/**
|
|
3839
|
+
* Execute queries as a specific database principal.
|
|
3840
|
+
*
|
|
3841
|
+
* Borrows a dedicated connection from the pool, switches identity
|
|
3842
|
+
* via dialect-specific SQL, and provides a scoped query interface.
|
|
3843
|
+
* Two modes: callback (auto-reverts) and explicit (caller reverts).
|
|
3844
|
+
*
|
|
3845
|
+
* @example
|
|
3846
|
+
* ```typescript
|
|
3847
|
+
* // Callback mode — auto-reverts, even on throw
|
|
3848
|
+
* const result = await ctx.impersonate('username', async (scope) => {
|
|
3849
|
+
* return scope.kysely.selectFrom('users').selectAll().execute();
|
|
3850
|
+
* });
|
|
3851
|
+
*
|
|
3852
|
+
* // Explicit mode — caller owns lifecycle
|
|
3853
|
+
* const scope = await ctx.impersonate('username');
|
|
3854
|
+
* const users = await scope.kysely.selectFrom('users').selectAll().execute();
|
|
3855
|
+
* await scope.revert();
|
|
3856
|
+
* ```
|
|
3857
|
+
*/
|
|
3858
|
+
impersonate<T>(username: string, fn: (scope: ImpersonatedScope<DB, Procs, Funcs>) => Promise<T>): Promise<T>;
|
|
3859
|
+
impersonate(username: string): Promise<ImpersonatedScope<DB, Procs, Funcs>>;
|
|
2007
3860
|
}
|
|
2008
3861
|
/**
|
|
2009
3862
|
* Error thrown when requireTest is enabled but config.isTest is false.
|
|
@@ -2072,7 +3925,7 @@ export declare class ProtectedConfigError extends Error {
|
|
|
2072
3925
|
* const ctx = await createContext()
|
|
2073
3926
|
* ```
|
|
2074
3927
|
*/
|
|
2075
|
-
export declare function createContext<DB = unknown>(options?: CreateContextOptions): Promise<Context<DB>>;
|
|
3928
|
+
export declare function createContext<DB = unknown, Procs = object, Funcs = object>(options?: CreateContextOptions): Promise<Context<DB, Procs, Funcs>>;
|
|
2076
3929
|
|
|
2077
3930
|
export {
|
|
2078
3931
|
Lock$1 as Lock,
|