@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/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 _parentId: bigint;
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
- parentId: bigint,
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._parentId = parentId;
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
- async _create(): Promise<void> {
124
+ /** @internal — fire-and-forget: sends creation reducer, resolves immediately */
125
+ _create(): void {
127
126
  const conn = this._sdk.conn;
128
- const exportToken = this._exportToken;
129
- const keyHash = this._keyHash;
130
- const timeoutSeconds = this._timeoutSeconds;
131
-
132
- if (this._parentId === 0n) {
133
- const id = await this._sdk.createFlowAndResolveId(
134
- () =>
135
- conn.reducers.createRootFlow({
136
- keyHash,
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
- const parentFlowId = this._parentId;
147
- const name = this._name;
148
- const id = await this._sdk.createFlowAndResolveId(
149
- () =>
150
- conn.reducers.createSubFlow({
151
- keyHash,
152
- parentFlowId,
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(); // flush any logs queued before ready
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
- console.warn(`[radish] Cannot log to finished flow`);
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-action. Returns immediately — creation runs in background. */
188
+ /** Create a sub-flow. Returns immediately — creation runs in background. */
203
189
  action(name: string, timeoutSeconds = 100): Flow {
204
- const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release, this._runId);
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(); // sync flush — sends over same WS, ordering preserved
231
+ this._drain();
239
232
  this._finished = true;
240
233
  this._sdk.conn.reducers.finishFlow({
241
234
  keyHash: this._keyHash,
242
- flowId: this._id!,
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
- flowId: this._id!,
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
- async exportID(): Promise<string> {
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
- flowId: this._id!,
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
- flowId: this._id!,
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 action.
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
- * // Manual — when you need more control
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
- try {
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 — creation runs in background, logs queue until ready
402
- const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
403
- root._create(); // fire-and-forget — resolves _ready when server assigns ID
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, 0n, "restored", 100, "", parsed.runId || "");
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
  }
@@ -12,7 +12,7 @@ import {
12
12
 
13
13
  export default {
14
14
  keyHash: __t.string(),
15
- flowId: __t.u64(),
15
+ exportToken: __t.string(),
16
16
  level: __t.string(),
17
17
  message: __t.string(),
18
18
  data: __t.string(),
@@ -12,6 +12,6 @@ import {
12
12
 
13
13
  export default {
14
14
  keyHash: __t.string(),
15
- flowId: __t.u64(),
15
+ exportToken: __t.string(),
16
16
  entries: __t.string(),
17
17
  };
@@ -12,7 +12,7 @@ import {
12
12
 
13
13
  export default {
14
14
  keyHash: __t.string(),
15
- parentFlowId: __t.u64(),
15
+ parentExportToken: __t.string(),
16
16
  name: __t.string(),
17
17
  timeoutSeconds: __t.u64(),
18
18
  exportToken: __t.string(),
@@ -12,7 +12,7 @@ import {
12
12
 
13
13
  export default {
14
14
  keyHash: __t.string(),
15
- flowId: __t.u64(),
15
+ exportToken: __t.string(),
16
16
  status: __t.string(),
17
17
  errorMessage: __t.string(),
18
18
  };
@@ -12,6 +12,6 @@ import {
12
12
 
13
13
  export default {
14
14
  keyHash: __t.string(),
15
- flowId: __t.u64(),
15
+ exportToken: __t.string(),
16
16
  name: __t.string(),
17
17
  };