@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/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  } from "spacetimedb";
19
19
  var add_log_reducer_default = {
20
20
  keyHash: __t.string(),
21
- flowId: __t.u64(),
21
+ exportToken: __t.string(),
22
22
  level: __t.string(),
23
23
  message: __t.string(),
24
24
  data: __t.string()
@@ -30,7 +30,7 @@ import {
30
30
  } from "spacetimedb";
31
31
  var add_logs_batch_reducer_default = {
32
32
  keyHash: __t2.string(),
33
- flowId: __t2.u64(),
33
+ exportToken: __t2.string(),
34
34
  entries: __t2.string()
35
35
  };
36
36
 
@@ -52,7 +52,7 @@ import {
52
52
  } from "spacetimedb";
53
53
  var create_sub_flow_reducer_default = {
54
54
  keyHash: __t4.string(),
55
- parentFlowId: __t4.u64(),
55
+ parentExportToken: __t4.string(),
56
56
  name: __t4.string(),
57
57
  timeoutSeconds: __t4.u64(),
58
58
  exportToken: __t4.string()
@@ -74,7 +74,7 @@ import {
74
74
  } from "spacetimedb";
75
75
  var finish_flow_reducer_default = {
76
76
  keyHash: __t6.string(),
77
- flowId: __t6.u64(),
77
+ exportToken: __t6.string(),
78
78
  status: __t6.string(),
79
79
  errorMessage: __t6.string()
80
80
  };
@@ -95,7 +95,7 @@ import {
95
95
  } from "spacetimedb";
96
96
  var start_action_reducer_default = {
97
97
  keyHash: __t8.string(),
98
- flowId: __t8.u64(),
98
+ exportToken: __t8.string(),
99
99
  name: __t8.string()
100
100
  };
101
101
 
@@ -283,15 +283,10 @@ class SdkConnection {
283
283
  _dbName;
284
284
  _conn = null;
285
285
  _connectPromise = null;
286
- _keyHash = null;
287
- _flowWaiters = new Map;
288
286
  constructor(host, dbName) {
289
287
  this._host = host;
290
288
  this._dbName = dbName;
291
289
  }
292
- setKeyHash(keyHash) {
293
- this._keyHash = keyHash;
294
- }
295
290
  async connect() {
296
291
  if (this._conn)
297
292
  return this._conn;
@@ -300,14 +295,7 @@ class SdkConnection {
300
295
  this._connectPromise = new Promise((resolve, reject) => {
301
296
  DbConnection.builder().withUri(this._host).withDatabaseName(this._dbName).onConnect((c, _identity, _token) => {
302
297
  this._conn = c;
303
- c.db.flow.onInsert((_ctx, row) => {
304
- const waiter = this._flowWaiters.get(row.exportToken);
305
- if (waiter) {
306
- this._flowWaiters.delete(row.exportToken);
307
- waiter(row.id);
308
- }
309
- });
310
- c.subscriptionBuilder().onApplied(() => resolve(c)).subscribe([`SELECT * FROM flow WHERE key_hash = '${this._keyHash}'`]);
298
+ resolve(c);
311
299
  }).onConnectError((_ctx, err) => {
312
300
  reject(new Error(`SpacetimeDB connection failed: ${err}`));
313
301
  }).build();
@@ -319,47 +307,6 @@ class SdkConnection {
319
307
  throw new Error("Not connected");
320
308
  return this._conn;
321
309
  }
322
- async createFlowAndResolveId(reducerCall, exportToken) {
323
- const conn = this.conn;
324
- for (const f of conn.db.flow.iter()) {
325
- if (f.exportToken === exportToken)
326
- return f.id;
327
- }
328
- return new Promise((resolve, reject) => {
329
- let resolved = false;
330
- this._flowWaiters.set(exportToken, (id) => {
331
- if (!resolved) {
332
- resolved = true;
333
- clearInterval(interval);
334
- resolve(id);
335
- }
336
- });
337
- reducerCall();
338
- const interval = setInterval(() => {
339
- if (resolved) {
340
- clearInterval(interval);
341
- return;
342
- }
343
- for (const f of conn.db.flow.iter()) {
344
- if (f.exportToken === exportToken) {
345
- resolved = true;
346
- clearInterval(interval);
347
- this._flowWaiters.delete(exportToken);
348
- resolve(f.id);
349
- return;
350
- }
351
- }
352
- }, 100);
353
- setTimeout(() => {
354
- if (!resolved) {
355
- resolved = true;
356
- clearInterval(interval);
357
- this._flowWaiters.delete(exportToken);
358
- reject(new Error(`Flow creation timed out for token ${exportToken}`));
359
- }
360
- }, 15000);
361
- });
362
- }
363
310
  disconnect() {
364
311
  if (this._conn) {
365
312
  this._conn.disconnect();
@@ -441,7 +388,6 @@ function generateToken() {
441
388
  class Flow {
442
389
  _sdk;
443
390
  _keyHash;
444
- _id = null;
445
391
  _exportToken;
446
392
  _ready;
447
393
  _resolveReady;
@@ -449,15 +395,15 @@ class Flow {
449
395
  _flushScheduled = false;
450
396
  _isReady = false;
451
397
  _finished = false;
452
- _parentId;
398
+ _parentExportToken;
453
399
  _name;
454
400
  _timeoutSeconds;
455
401
  _release;
456
402
  _runId;
457
- constructor(sdk, keyHash, parentId, name, timeoutSeconds, release = "", runId = "") {
403
+ constructor(sdk, keyHash, parentExportToken, name, timeoutSeconds, release = "", runId = "") {
458
404
  this._sdk = sdk;
459
405
  this._keyHash = keyHash;
460
- this._parentId = parentId;
406
+ this._parentExportToken = parentExportToken;
461
407
  this._name = name;
462
408
  this._timeoutSeconds = !timeoutSeconds || timeoutSeconds === Infinity ? 0n : BigInt(timeoutSeconds);
463
409
  this._release = release;
@@ -467,31 +413,24 @@ class Flow {
467
413
  this._resolveReady = resolve;
468
414
  });
469
415
  }
470
- async _create() {
416
+ _create() {
471
417
  const conn = this._sdk.conn;
472
- const exportToken = this._exportToken;
473
- const keyHash = this._keyHash;
474
- const timeoutSeconds = this._timeoutSeconds;
475
- if (this._parentId === 0n) {
476
- const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createRootFlow({
477
- keyHash,
418
+ if (this._parentExportToken === null) {
419
+ conn.reducers.createRootFlow({
420
+ keyHash: this._keyHash,
478
421
  runId: this._runId,
479
- timeoutSeconds,
480
- exportToken,
422
+ timeoutSeconds: this._timeoutSeconds,
423
+ exportToken: this._exportToken,
481
424
  release: this._release
482
- }), exportToken);
483
- this._id = id;
425
+ });
484
426
  } else {
485
- const parentFlowId = this._parentId;
486
- const name = this._name;
487
- const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createSubFlow({
488
- keyHash,
489
- parentFlowId,
490
- name,
491
- timeoutSeconds,
492
- exportToken
493
- }), exportToken);
494
- this._id = id;
427
+ conn.reducers.createSubFlow({
428
+ keyHash: this._keyHash,
429
+ parentExportToken: this._parentExportToken,
430
+ name: this._name,
431
+ timeoutSeconds: this._timeoutSeconds,
432
+ exportToken: this._exportToken
433
+ });
495
434
  }
496
435
  this._isReady = true;
497
436
  this._resolveReady();
@@ -500,7 +439,7 @@ class Flow {
500
439
  static MAX_PENDING = 1e4;
501
440
  log(message, data, level = "info") {
502
441
  if (this._finished) {
503
- console.warn(`[radish] Cannot log to finished flow`);
442
+ _origConsole.warn(`[radish] Cannot log to finished flow`);
504
443
  return this;
505
444
  }
506
445
  if (this._pendingLogs.length >= Flow.MAX_PENDING) {
@@ -528,9 +467,8 @@ class Flow {
528
467
  return this.log(message, data, "debug");
529
468
  }
530
469
  action(name, timeoutSeconds = 100) {
531
- const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release, this._runId);
470
+ const child = new Flow(this._sdk, this._keyHash, this._exportToken, name, timeoutSeconds, this._release, this._runId);
532
471
  this._ready.then(() => {
533
- child._parentId = this._id;
534
472
  child._create();
535
473
  });
536
474
  return child;
@@ -561,7 +499,7 @@ class Flow {
561
499
  this._finished = true;
562
500
  this._sdk.conn.reducers.finishFlow({
563
501
  keyHash: this._keyHash,
564
- flowId: this._id,
502
+ exportToken: this._exportToken,
565
503
  status: "finished",
566
504
  errorMessage: ""
567
505
  });
@@ -576,7 +514,7 @@ class Flow {
576
514
  this._finished = true;
577
515
  this._sdk.conn.reducers.finishFlow({
578
516
  keyHash: this._keyHash,
579
- flowId: this._id,
517
+ exportToken: this._exportToken,
580
518
  status: "error",
581
519
  errorMessage
582
520
  });
@@ -584,19 +522,16 @@ class Flow {
584
522
  get runId() {
585
523
  return this._runId;
586
524
  }
587
- async exportID() {
588
- await this._ready;
525
+ get token() {
526
+ return this._exportToken;
527
+ }
528
+ exportID() {
589
529
  return JSON.stringify({
590
- flowId: this._id.toString(),
591
530
  exportToken: this._exportToken,
592
531
  keyHash: this._keyHash,
593
532
  runId: this._runId
594
533
  });
595
534
  }
596
- async getId() {
597
- await this._ready;
598
- return this._id;
599
- }
600
535
  disconnect() {
601
536
  this._sdk.disconnect();
602
537
  }
@@ -623,7 +558,7 @@ class Flow {
623
558
  const e = batch[0];
624
559
  conn.reducers.addLog({
625
560
  keyHash: this._keyHash,
626
- flowId: this._id,
561
+ exportToken: this._exportToken,
627
562
  level: e.level,
628
563
  message: e.message,
629
564
  data: e.data
@@ -631,7 +566,7 @@ class Flow {
631
566
  } else {
632
567
  conn.reducers.addLogsBatch({
633
568
  keyHash: this._keyHash,
634
- flowId: this._id,
569
+ exportToken: this._exportToken,
635
570
  entries: JSON.stringify(batch)
636
571
  });
637
572
  }
@@ -656,16 +591,13 @@ async function RL(secretKey, options = {}) {
656
591
  const retentionDays = parseRetention(retention);
657
592
  const keyHash = await hashKey(secretKey);
658
593
  const sdk = new SdkConnection(host, dbName);
659
- sdk.setKeyHash(keyHash);
660
594
  try {
661
595
  await sdk.connect();
662
596
  } catch (e) {
663
597
  throw new Error(`Failed to connect to Radish (${host}/${dbName}): ${e instanceof Error ? e.message : e}`);
664
598
  }
665
- try {
666
- sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
667
- } catch {}
668
- const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
599
+ sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
600
+ const root = new Flow(sdk, keyHash, null, "/", 0, release, runId);
669
601
  root._create();
670
602
  return root;
671
603
  }
@@ -678,9 +610,9 @@ async function restoreFlow(secretKey, exportedId, options = {}) {
678
610
  }
679
611
  const sdk = new SdkConnection(host, dbName);
680
612
  await sdk.connect();
681
- const flow = new Flow(sdk, keyHash, 0n, "restored", 100, "", parsed.runId || "");
682
- flow._id = BigInt(parsed.flowId);
613
+ const flow = new Flow(sdk, keyHash, null, "restored", 100, "", parsed.runId || "");
683
614
  flow._exportToken = parsed.exportToken;
615
+ flow._isReady = true;
684
616
  flow._resolveReady();
685
617
  return flow;
686
618
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radishbot/sdk",
3
- "version": "0.7.2",
3
+ "version": "0.8.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  }
13
13
  },
14
14
  "bin": {
15
- "radish": "./src/cli.ts"
15
+ "radish": "./dist/cli.js"
16
16
  },
17
17
  "files": [
18
18
  "src",
@@ -20,7 +20,7 @@
20
20
  "README.md"
21
21
  ],
22
22
  "scripts": {
23
- "build": "bun build ./src/index.ts --outdir dist --target node --format esm --external spacetimedb --external ws",
23
+ "build": "bun build ./src/index.ts --outdir dist --target node --format esm --external spacetimedb --external ws && bun build ./src/cli.ts --outfile dist/cli.js --target node --format esm --external spacetimedb --external ws",
24
24
  "prepublishOnly": "bun run build",
25
25
  "cli": "bun run ./src/cli.ts"
26
26
  },
package/src/cli.ts CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * Radish CLI — inspect flows and logs from the terminal.
4
4
  *
package/src/connection.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * SpacetimeDB connection wrapper for the Radish SDK.
3
- * Uses the generated bindings + SpacetimeDB WebSocket client.
3
+ * No subscription needed all operations use exportToken (fire-and-forget reducers).
4
4
  */
5
5
  import { DbConnection as StdbConnection } from "./module_bindings";
6
6
 
@@ -9,20 +9,12 @@ export class SdkConnection {
9
9
  private _dbName: string;
10
10
  private _conn: StdbConnection | null = null;
11
11
  private _connectPromise: Promise<StdbConnection> | null = null;
12
- private _keyHash: string | null = null;
13
-
14
- // Callbacks waiting for flow creation by exportToken
15
- private _flowWaiters = new Map<string, (id: bigint) => void>();
16
12
 
17
13
  constructor(host: string, dbName: string) {
18
14
  this._host = host;
19
15
  this._dbName = dbName;
20
16
  }
21
17
 
22
- setKeyHash(keyHash: string): void {
23
- this._keyHash = keyHash;
24
- }
25
-
26
18
  async connect(): Promise<StdbConnection> {
27
19
  if (this._conn) return this._conn;
28
20
  if (this._connectPromise) return this._connectPromise;
@@ -33,19 +25,7 @@ export class SdkConnection {
33
25
  .withDatabaseName(this._dbName)
34
26
  .onConnect((c, _identity, _token) => {
35
27
  this._conn = c;
36
-
37
- // Resolve flow waiters immediately when new flows arrive
38
- c.db.flow.onInsert((_ctx, row) => {
39
- const waiter = this._flowWaiters.get(row.exportToken);
40
- if (waiter) {
41
- this._flowWaiters.delete(row.exportToken);
42
- waiter(row.id);
43
- }
44
- });
45
-
46
- c.subscriptionBuilder()
47
- .onApplied(() => resolve(c))
48
- .subscribe([`SELECT * FROM flow WHERE key_hash = '${this._keyHash}'`]);
28
+ resolve(c);
49
29
  })
50
30
  .onConnectError((_ctx, err) => {
51
31
  reject(new Error(`SpacetimeDB connection failed: ${err}`));
@@ -61,62 +41,6 @@ export class SdkConnection {
61
41
  return this._conn;
62
42
  }
63
43
 
64
- /**
65
- * Call a reducer and wait for the flow to appear in the subscription.
66
- * Returns the server-assigned flow ID.
67
- */
68
- async createFlowAndResolveId(reducerCall: () => void, exportToken: string): Promise<bigint> {
69
- const conn = this.conn;
70
-
71
- // Check if flow already exists (from a previous subscription update)
72
- for (const f of conn.db.flow.iter()) {
73
- if (f.exportToken === exportToken) return f.id;
74
- }
75
-
76
- return new Promise<bigint>((resolve, reject) => {
77
- let resolved = false;
78
-
79
- // Register waiter — triggered by onInsert handler in connect()
80
- this._flowWaiters.set(exportToken, (id) => {
81
- if (!resolved) {
82
- resolved = true;
83
- clearInterval(interval);
84
- resolve(id);
85
- }
86
- });
87
-
88
- // Call the reducer
89
- reducerCall();
90
-
91
- // Poll as fallback in case onInsert fires before waiter is registered
92
- const interval = setInterval(() => {
93
- if (resolved) {
94
- clearInterval(interval);
95
- return;
96
- }
97
- for (const f of conn.db.flow.iter()) {
98
- if (f.exportToken === exportToken) {
99
- resolved = true;
100
- clearInterval(interval);
101
- this._flowWaiters.delete(exportToken);
102
- resolve(f.id);
103
- return;
104
- }
105
- }
106
- }, 100);
107
-
108
- // Timeout after 15 seconds (properly rejects the promise)
109
- setTimeout(() => {
110
- if (!resolved) {
111
- resolved = true;
112
- clearInterval(interval);
113
- this._flowWaiters.delete(exportToken);
114
- reject(new Error(`Flow creation timed out for token ${exportToken}`));
115
- }
116
- }, 15_000);
117
- });
118
- }
119
-
120
44
  disconnect(): void {
121
45
  if (this._conn) {
122
46
  this._conn.disconnect();