@radishbot/sdk 0.7.2 → 0.8.1
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/cli.js +696 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -105
- package/package.json +3 -3
- package/src/cli.ts +1 -1
- package/src/connection.ts +2 -78
- package/src/index.ts +55 -78
- package/src/module_bindings/add_log_reducer.ts +1 -1
- package/src/module_bindings/add_logs_batch_reducer.ts +1 -1
- package/src/module_bindings/create_sub_flow_reducer.ts +1 -1
- package/src/module_bindings/finish_flow_reducer.ts +1 -1
- package/src/module_bindings/start_action_reducer.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -85,7 +85,6 @@ function generateToken(): string {
|
|
|
85
85
|
export class Flow {
|
|
86
86
|
private _sdk: SdkConnection;
|
|
87
87
|
private _keyHash: string;
|
|
88
|
-
private _id: bigint | null = null;
|
|
89
88
|
private _exportToken: string;
|
|
90
89
|
private _ready: Promise<void>;
|
|
91
90
|
private _resolveReady!: () => void;
|
|
@@ -93,7 +92,7 @@ export class Flow {
|
|
|
93
92
|
private _flushScheduled = false;
|
|
94
93
|
private _isReady = false;
|
|
95
94
|
private _finished = false;
|
|
96
|
-
private
|
|
95
|
+
private _parentExportToken: string | null;
|
|
97
96
|
private _name: string;
|
|
98
97
|
private _timeoutSeconds: bigint;
|
|
99
98
|
private _release: string;
|
|
@@ -103,7 +102,7 @@ export class Flow {
|
|
|
103
102
|
constructor(
|
|
104
103
|
sdk: SdkConnection,
|
|
105
104
|
keyHash: string,
|
|
106
|
-
|
|
105
|
+
parentExportToken: string | null,
|
|
107
106
|
name: string,
|
|
108
107
|
timeoutSeconds: number,
|
|
109
108
|
release: string = "",
|
|
@@ -111,7 +110,7 @@ export class Flow {
|
|
|
111
110
|
) {
|
|
112
111
|
this._sdk = sdk;
|
|
113
112
|
this._keyHash = keyHash;
|
|
114
|
-
this.
|
|
113
|
+
this._parentExportToken = parentExportToken;
|
|
115
114
|
this._name = name;
|
|
116
115
|
this._timeoutSeconds = !timeoutSeconds || timeoutSeconds === Infinity ? 0n : BigInt(timeoutSeconds);
|
|
117
116
|
this._release = release;
|
|
@@ -122,45 +121,33 @@ export class Flow {
|
|
|
122
121
|
});
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
/** @internal */
|
|
126
|
-
|
|
124
|
+
/** @internal — fire-and-forget: sends creation reducer, resolves immediately */
|
|
125
|
+
_create(): void {
|
|
127
126
|
const conn = this._sdk.conn;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
runId: this._runId,
|
|
138
|
-
timeoutSeconds,
|
|
139
|
-
exportToken,
|
|
140
|
-
release: this._release,
|
|
141
|
-
}),
|
|
142
|
-
exportToken,
|
|
143
|
-
);
|
|
144
|
-
this._id = id;
|
|
127
|
+
|
|
128
|
+
if (this._parentExportToken === null) {
|
|
129
|
+
conn.reducers.createRootFlow({
|
|
130
|
+
keyHash: this._keyHash,
|
|
131
|
+
runId: this._runId,
|
|
132
|
+
timeoutSeconds: this._timeoutSeconds,
|
|
133
|
+
exportToken: this._exportToken,
|
|
134
|
+
release: this._release,
|
|
135
|
+
});
|
|
145
136
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
name,
|
|
154
|
-
timeoutSeconds,
|
|
155
|
-
exportToken,
|
|
156
|
-
}),
|
|
157
|
-
exportToken,
|
|
158
|
-
);
|
|
159
|
-
this._id = id;
|
|
137
|
+
conn.reducers.createSubFlow({
|
|
138
|
+
keyHash: this._keyHash,
|
|
139
|
+
parentExportToken: this._parentExportToken,
|
|
140
|
+
name: this._name,
|
|
141
|
+
timeoutSeconds: this._timeoutSeconds,
|
|
142
|
+
exportToken: this._exportToken,
|
|
143
|
+
});
|
|
160
144
|
}
|
|
145
|
+
|
|
146
|
+
// Ready immediately — server processes messages in order,
|
|
147
|
+
// so any subsequent reducers run after the creation above
|
|
161
148
|
this._isReady = true;
|
|
162
149
|
this._resolveReady();
|
|
163
|
-
this._drain();
|
|
150
|
+
this._drain();
|
|
164
151
|
}
|
|
165
152
|
|
|
166
153
|
/** Max pending logs before oldest are dropped (prevents memory issues at high volume) */
|
|
@@ -169,10 +156,9 @@ export class Flow {
|
|
|
169
156
|
/** Log a message with optional data */
|
|
170
157
|
log(message: string, data?: unknown, level: LogLevel = "info"): this {
|
|
171
158
|
if (this._finished) {
|
|
172
|
-
|
|
159
|
+
_origConsole.warn(`[radish] Cannot log to finished flow`);
|
|
173
160
|
return this;
|
|
174
161
|
}
|
|
175
|
-
// Drop oldest logs if buffer is full (backpressure)
|
|
176
162
|
if (this._pendingLogs.length >= Flow.MAX_PENDING) {
|
|
177
163
|
const dropped = this._pendingLogs.length - Flow.MAX_PENDING + 1;
|
|
178
164
|
this._pendingLogs.splice(0, dropped);
|
|
@@ -199,11 +185,18 @@ export class Flow {
|
|
|
199
185
|
return this.log(message, data, "debug");
|
|
200
186
|
}
|
|
201
187
|
|
|
202
|
-
/** Create a sub-
|
|
188
|
+
/** Create a sub-flow. Returns immediately — creation runs in background. */
|
|
203
189
|
action(name: string, timeoutSeconds = 100): Flow {
|
|
204
|
-
const child = new Flow(
|
|
190
|
+
const child = new Flow(
|
|
191
|
+
this._sdk,
|
|
192
|
+
this._keyHash,
|
|
193
|
+
this._exportToken,
|
|
194
|
+
name,
|
|
195
|
+
timeoutSeconds,
|
|
196
|
+
this._release,
|
|
197
|
+
this._runId,
|
|
198
|
+
);
|
|
205
199
|
this._ready.then(() => {
|
|
206
|
-
(child as any)._parentId = this._id!;
|
|
207
200
|
child._create();
|
|
208
201
|
});
|
|
209
202
|
return child;
|
|
@@ -235,11 +228,11 @@ export class Flow {
|
|
|
235
228
|
/** Finish this flow successfully */
|
|
236
229
|
async finish(): Promise<void> {
|
|
237
230
|
await this._ready;
|
|
238
|
-
this._drain();
|
|
231
|
+
this._drain();
|
|
239
232
|
this._finished = true;
|
|
240
233
|
this._sdk.conn.reducers.finishFlow({
|
|
241
234
|
keyHash: this._keyHash,
|
|
242
|
-
|
|
235
|
+
exportToken: this._exportToken,
|
|
243
236
|
status: "finished",
|
|
244
237
|
errorMessage: "",
|
|
245
238
|
});
|
|
@@ -256,7 +249,7 @@ export class Flow {
|
|
|
256
249
|
this._finished = true;
|
|
257
250
|
this._sdk.conn.reducers.finishFlow({
|
|
258
251
|
keyHash: this._keyHash,
|
|
259
|
-
|
|
252
|
+
exportToken: this._exportToken,
|
|
260
253
|
status: "error",
|
|
261
254
|
errorMessage,
|
|
262
255
|
});
|
|
@@ -267,23 +260,20 @@ export class Flow {
|
|
|
267
260
|
return this._runId;
|
|
268
261
|
}
|
|
269
262
|
|
|
263
|
+
/** Get the export token for this flow */
|
|
264
|
+
get token(): string {
|
|
265
|
+
return this._exportToken;
|
|
266
|
+
}
|
|
267
|
+
|
|
270
268
|
/** Export this flow's handle for restoration in another context */
|
|
271
|
-
|
|
272
|
-
await this._ready;
|
|
269
|
+
exportID(): string {
|
|
273
270
|
return JSON.stringify({
|
|
274
|
-
flowId: this._id!.toString(),
|
|
275
271
|
exportToken: this._exportToken,
|
|
276
272
|
keyHash: this._keyHash,
|
|
277
273
|
runId: this._runId,
|
|
278
274
|
});
|
|
279
275
|
}
|
|
280
276
|
|
|
281
|
-
/** Get the resolved server-assigned flow ID */
|
|
282
|
-
async getId(): Promise<bigint> {
|
|
283
|
-
await this._ready;
|
|
284
|
-
return this._id!;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
277
|
/** Disconnect the underlying SpacetimeDB connection */
|
|
288
278
|
disconnect(): void {
|
|
289
279
|
this._sdk.disconnect();
|
|
@@ -292,7 +282,6 @@ export class Flow {
|
|
|
292
282
|
/** Finish the flow and disconnect */
|
|
293
283
|
async finishAndDisconnect(): Promise<void> {
|
|
294
284
|
await this.finish();
|
|
295
|
-
// Small delay to allow the finish reducer to be sent
|
|
296
285
|
await new Promise((r) => setTimeout(r, 100));
|
|
297
286
|
this.disconnect();
|
|
298
287
|
}
|
|
@@ -317,7 +306,7 @@ export class Flow {
|
|
|
317
306
|
const e = batch[0];
|
|
318
307
|
conn.reducers.addLog({
|
|
319
308
|
keyHash: this._keyHash,
|
|
320
|
-
|
|
309
|
+
exportToken: this._exportToken,
|
|
321
310
|
level: e.level,
|
|
322
311
|
message: e.message,
|
|
323
312
|
data: e.data,
|
|
@@ -325,7 +314,7 @@ export class Flow {
|
|
|
325
314
|
} else {
|
|
326
315
|
conn.reducers.addLogsBatch({
|
|
327
316
|
keyHash: this._keyHash,
|
|
328
|
-
|
|
317
|
+
exportToken: this._exportToken,
|
|
329
318
|
entries: JSON.stringify(batch),
|
|
330
319
|
});
|
|
331
320
|
}
|
|
@@ -339,7 +328,6 @@ export interface RLOptions {
|
|
|
339
328
|
defaultTimeout?: number;
|
|
340
329
|
release?: string;
|
|
341
330
|
retention?: string;
|
|
342
|
-
/** Run ID — groups flows across processes. Auto-generated if not provided. */
|
|
343
331
|
runId?: string;
|
|
344
332
|
}
|
|
345
333
|
|
|
@@ -350,24 +338,18 @@ function parseRetention(retention: string): number {
|
|
|
350
338
|
}
|
|
351
339
|
|
|
352
340
|
/**
|
|
353
|
-
* Create a Radish Logger instance. Returns the root
|
|
341
|
+
* Create a Radish Logger instance. Returns the root flow.
|
|
354
342
|
*
|
|
355
343
|
* ```ts
|
|
356
344
|
* const root = await RL('my-secret-key');
|
|
357
345
|
*
|
|
358
|
-
* // Auto-managed — auto-finish on return, auto-error on throw
|
|
359
346
|
* await root.a('request', async (req) => {
|
|
360
347
|
* console.log('GET /api/users');
|
|
361
348
|
* const rows = await req.a('db_query', () => db.query('SELECT ...'));
|
|
362
349
|
* console.log('Done', { count: rows.length });
|
|
363
350
|
* });
|
|
364
351
|
*
|
|
365
|
-
*
|
|
366
|
-
* const ws = root.action('websocket');
|
|
367
|
-
* ws.info('Connected');
|
|
368
|
-
* await ws.finish();
|
|
369
|
-
*
|
|
370
|
-
* await root.finish();
|
|
352
|
+
* await root.finishAndDisconnect();
|
|
371
353
|
* ```
|
|
372
354
|
*/
|
|
373
355
|
export async function RL(secretKey: string, options: RLOptions = {}): Promise<Flow> {
|
|
@@ -384,7 +366,6 @@ export async function RL(secretKey: string, options: RLOptions = {}): Promise<Fl
|
|
|
384
366
|
const retentionDays = parseRetention(retention);
|
|
385
367
|
const keyHash = await hashKey(secretKey);
|
|
386
368
|
const sdk = new SdkConnection(host, dbName);
|
|
387
|
-
sdk.setKeyHash(keyHash);
|
|
388
369
|
try {
|
|
389
370
|
await sdk.connect();
|
|
390
371
|
} catch (e) {
|
|
@@ -392,15 +373,11 @@ export async function RL(secretKey: string, options: RLOptions = {}): Promise<Fl
|
|
|
392
373
|
}
|
|
393
374
|
|
|
394
375
|
// Register key (idempotent — updates retention if changed)
|
|
395
|
-
|
|
396
|
-
sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
|
|
397
|
-
} catch {
|
|
398
|
-
// Already registered
|
|
399
|
-
}
|
|
376
|
+
sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
|
|
400
377
|
|
|
401
|
-
// Root flow —
|
|
402
|
-
const root = new Flow(sdk, keyHash,
|
|
403
|
-
root._create();
|
|
378
|
+
// Root flow — fire-and-forget, ready immediately
|
|
379
|
+
const root = new Flow(sdk, keyHash, null, "/", 0, release, runId);
|
|
380
|
+
root._create();
|
|
404
381
|
return root;
|
|
405
382
|
}
|
|
406
383
|
|
|
@@ -417,9 +394,9 @@ export async function restoreFlow(secretKey: string, exportedId: string, options
|
|
|
417
394
|
const sdk = new SdkConnection(host, dbName);
|
|
418
395
|
await sdk.connect();
|
|
419
396
|
|
|
420
|
-
const flow = new Flow(sdk, keyHash,
|
|
421
|
-
(flow as any)._id = BigInt(parsed.flowId);
|
|
397
|
+
const flow = new Flow(sdk, keyHash, null, "restored", 100, "", parsed.runId || "");
|
|
422
398
|
(flow as any)._exportToken = parsed.exportToken;
|
|
399
|
+
(flow as any)._isReady = true;
|
|
423
400
|
(flow as any)._resolveReady();
|
|
424
401
|
return flow;
|
|
425
402
|
}
|