@radishbot/sdk 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * SpacetimeDB connection wrapper for the Radish SDK.
3
+ * Uses the generated bindings + SpacetimeDB WebSocket client.
4
+ */
5
+ import { DbConnection as StdbConnection } from './module_bindings';
6
+ export declare class SdkConnection {
7
+ private _host;
8
+ private _dbName;
9
+ private _conn;
10
+ private _connectPromise;
11
+ private _timeoutInterval;
12
+ private _keyHash;
13
+ private _flowWaiters;
14
+ constructor(host: string, dbName: string);
15
+ setKeyHash(keyHash: string): void;
16
+ connect(): Promise<StdbConnection>;
17
+ get conn(): StdbConnection;
18
+ /**
19
+ * Call a reducer and wait for the flow to appear in the subscription.
20
+ * Returns the server-assigned flow ID.
21
+ */
22
+ createFlowAndResolveId(reducerCall: () => void, exportToken: string): Promise<bigint>;
23
+ disconnect(): void;
24
+ }
@@ -0,0 +1,31 @@
1
+ export type LogLevel = "info" | "warn" | "error" | "debug";
2
+
3
+ export declare class Flow {
4
+ log(message: string, data?: unknown, level?: LogLevel): this;
5
+ info(message: string, data?: unknown): this;
6
+ warn(message: string, data?: unknown): this;
7
+ error(message: string, data?: unknown): this;
8
+ debug(message: string, data?: unknown): this;
9
+ action(name: string, timeoutSeconds?: number): Flow;
10
+ flow(name: string, timeoutSeconds?: number): Flow;
11
+ a<T>(name: string, fn: (action: Flow) => T | Promise<T>, timeoutSeconds?: number): Promise<T>;
12
+ finish(): Promise<void>;
13
+ finishWithError(err?: Error | string): Promise<void>;
14
+ exportID(): Promise<string>;
15
+ getId(): Promise<bigint>;
16
+ disconnect(): void;
17
+ finishAndDisconnect(): Promise<void>;
18
+ }
19
+
20
+ export interface RLOptions {
21
+ host?: string;
22
+ dbName?: string;
23
+ label?: string;
24
+ defaultTimeout?: number;
25
+ release?: string;
26
+ retention?: string;
27
+ }
28
+
29
+ export declare function RL(secretKey: string, options?: RLOptions): Promise<Flow>;
30
+ export declare function restoreFlow(secretKey: string, exportedId: string, options?: RLOptions): Promise<Flow>;
31
+ export declare function generateKey(): string;
package/dist/index.js ADDED
@@ -0,0 +1,688 @@
1
+ // src/module_bindings/index.ts
2
+ import {
3
+ DbConnectionBuilder as __DbConnectionBuilder,
4
+ DbConnectionImpl as __DbConnectionImpl,
5
+ SubscriptionBuilderImpl as __SubscriptionBuilderImpl,
6
+ convertToAccessorMap as __convertToAccessorMap,
7
+ makeQueryBuilder as __makeQueryBuilder,
8
+ procedures as __procedures,
9
+ reducerSchema as __reducerSchema,
10
+ reducers as __reducers,
11
+ schema as __schema,
12
+ table as __table
13
+ } from "spacetimedb";
14
+
15
+ // src/module_bindings/add_log_reducer.ts
16
+ import {
17
+ t as __t
18
+ } from "spacetimedb";
19
+ var add_log_reducer_default = {
20
+ keyHash: __t.string(),
21
+ flowId: __t.u64(),
22
+ level: __t.string(),
23
+ message: __t.string(),
24
+ data: __t.string()
25
+ };
26
+
27
+ // src/module_bindings/add_logs_batch_reducer.ts
28
+ import {
29
+ t as __t2
30
+ } from "spacetimedb";
31
+ var add_logs_batch_reducer_default = {
32
+ keyHash: __t2.string(),
33
+ flowId: __t2.u64(),
34
+ entries: __t2.string()
35
+ };
36
+
37
+ // src/module_bindings/check_timeouts_reducer.ts
38
+ import {
39
+ t as __t3
40
+ } from "spacetimedb";
41
+ var check_timeouts_reducer_default = {
42
+ keyHash: __t3.string()
43
+ };
44
+
45
+ // src/module_bindings/create_root_flow_reducer.ts
46
+ import {
47
+ t as __t4
48
+ } from "spacetimedb";
49
+ var create_root_flow_reducer_default = {
50
+ keyHash: __t4.string(),
51
+ timeoutSeconds: __t4.u64(),
52
+ exportToken: __t4.string(),
53
+ release: __t4.string()
54
+ };
55
+
56
+ // src/module_bindings/create_sub_flow_reducer.ts
57
+ import {
58
+ t as __t5
59
+ } from "spacetimedb";
60
+ var create_sub_flow_reducer_default = {
61
+ keyHash: __t5.string(),
62
+ parentFlowId: __t5.u64(),
63
+ name: __t5.string(),
64
+ timeoutSeconds: __t5.u64(),
65
+ exportToken: __t5.string()
66
+ };
67
+
68
+ // src/module_bindings/finish_action_reducer.ts
69
+ import {
70
+ t as __t6
71
+ } from "spacetimedb";
72
+ var finish_action_reducer_default = {
73
+ keyHash: __t6.string(),
74
+ actionId: __t6.u64(),
75
+ status: __t6.string()
76
+ };
77
+
78
+ // src/module_bindings/finish_flow_reducer.ts
79
+ import {
80
+ t as __t7
81
+ } from "spacetimedb";
82
+ var finish_flow_reducer_default = {
83
+ keyHash: __t7.string(),
84
+ flowId: __t7.u64(),
85
+ status: __t7.string(),
86
+ errorMessage: __t7.string()
87
+ };
88
+
89
+ // src/module_bindings/register_key_reducer.ts
90
+ import {
91
+ t as __t8
92
+ } from "spacetimedb";
93
+ var register_key_reducer_default = {
94
+ keyHash: __t8.string(),
95
+ label: __t8.string(),
96
+ retentionDays: __t8.u64()
97
+ };
98
+
99
+ // src/module_bindings/start_action_reducer.ts
100
+ import {
101
+ t as __t9
102
+ } from "spacetimedb";
103
+ var start_action_reducer_default = {
104
+ keyHash: __t9.string(),
105
+ flowId: __t9.u64(),
106
+ name: __t9.string()
107
+ };
108
+
109
+ // src/module_bindings/update_error_group_status_reducer.ts
110
+ import {
111
+ t as __t10
112
+ } from "spacetimedb";
113
+ var update_error_group_status_reducer_default = {
114
+ keyHash: __t10.string(),
115
+ errorGroupId: __t10.u64(),
116
+ status: __t10.string()
117
+ };
118
+
119
+ // src/module_bindings/action_table.ts
120
+ import {
121
+ t as __t11
122
+ } from "spacetimedb";
123
+ var action_table_default = __t11.row({
124
+ id: __t11.u64().primaryKey(),
125
+ flowId: __t11.u64().name("flow_id"),
126
+ name: __t11.string(),
127
+ status: __t11.string(),
128
+ createdAt: __t11.timestamp().name("created_at"),
129
+ finishedAt: __t11.u64().name("finished_at")
130
+ });
131
+
132
+ // src/module_bindings/api_key_table.ts
133
+ import {
134
+ t as __t12
135
+ } from "spacetimedb";
136
+ var api_key_table_default = __t12.row({
137
+ keyHash: __t12.string().primaryKey().name("key_hash"),
138
+ label: __t12.string(),
139
+ retentionDays: __t12.u64().name("retention_days"),
140
+ createdAt: __t12.timestamp().name("created_at")
141
+ });
142
+
143
+ // src/module_bindings/error_group_table.ts
144
+ import {
145
+ t as __t13
146
+ } from "spacetimedb";
147
+ var error_group_table_default = __t13.row({
148
+ id: __t13.u64().primaryKey(),
149
+ keyHash: __t13.string().name("key_hash"),
150
+ fingerprint: __t13.string(),
151
+ message: __t13.string(),
152
+ path: __t13.string(),
153
+ release: __t13.string(),
154
+ count: __t13.u64(),
155
+ status: __t13.string(),
156
+ firstSeenAt: __t13.timestamp().name("first_seen_at"),
157
+ lastSeenAt: __t13.u64().name("last_seen_at"),
158
+ lastFlowId: __t13.u64().name("last_flow_id")
159
+ });
160
+
161
+ // src/module_bindings/flow_table.ts
162
+ import {
163
+ t as __t14
164
+ } from "spacetimedb";
165
+ var flow_table_default = __t14.row({
166
+ id: __t14.u64().primaryKey(),
167
+ keyHash: __t14.string().name("key_hash"),
168
+ parentFlowId: __t14.u64().name("parent_flow_id"),
169
+ name: __t14.string(),
170
+ path: __t14.string(),
171
+ status: __t14.string(),
172
+ release: __t14.string(),
173
+ timeoutSeconds: __t14.u64().name("timeout_seconds"),
174
+ createdAt: __t14.timestamp().name("created_at"),
175
+ finishedAt: __t14.u64().name("finished_at"),
176
+ exportToken: __t14.string().name("export_token")
177
+ });
178
+
179
+ // src/module_bindings/log_entry_table.ts
180
+ import {
181
+ t as __t15
182
+ } from "spacetimedb";
183
+ var log_entry_table_default = __t15.row({
184
+ id: __t15.u64().primaryKey(),
185
+ flowId: __t15.u64().name("flow_id"),
186
+ level: __t15.string(),
187
+ message: __t15.string(),
188
+ data: __t15.string(),
189
+ createdAt: __t15.timestamp().name("created_at")
190
+ });
191
+
192
+ // src/module_bindings/index.ts
193
+ var tablesSchema = __schema({
194
+ action: __table({
195
+ name: "action",
196
+ indexes: [
197
+ { name: "id", algorithm: "btree", columns: [
198
+ "id"
199
+ ] }
200
+ ],
201
+ constraints: [
202
+ { name: "action_id_key", constraint: "unique", columns: ["id"] }
203
+ ]
204
+ }, action_table_default),
205
+ apiKey: __table({
206
+ name: "api_key",
207
+ indexes: [
208
+ { name: "keyHash", algorithm: "btree", columns: [
209
+ "keyHash"
210
+ ] }
211
+ ],
212
+ constraints: [
213
+ { name: "api_key_key_hash_key", constraint: "unique", columns: ["keyHash"] }
214
+ ]
215
+ }, api_key_table_default),
216
+ errorGroup: __table({
217
+ name: "error_group",
218
+ indexes: [
219
+ { name: "fingerprint", algorithm: "btree", columns: [
220
+ "fingerprint"
221
+ ] },
222
+ { name: "id", algorithm: "btree", columns: [
223
+ "id"
224
+ ] }
225
+ ],
226
+ constraints: [
227
+ { name: "error_group_fingerprint_key", constraint: "unique", columns: ["fingerprint"] },
228
+ { name: "error_group_id_key", constraint: "unique", columns: ["id"] }
229
+ ]
230
+ }, error_group_table_default),
231
+ flow: __table({
232
+ name: "flow",
233
+ indexes: [
234
+ { name: "exportToken", algorithm: "btree", columns: [
235
+ "exportToken"
236
+ ] },
237
+ { name: "id", algorithm: "btree", columns: [
238
+ "id"
239
+ ] }
240
+ ],
241
+ constraints: [
242
+ { name: "flow_export_token_key", constraint: "unique", columns: ["exportToken"] },
243
+ { name: "flow_id_key", constraint: "unique", columns: ["id"] }
244
+ ]
245
+ }, flow_table_default),
246
+ logEntry: __table({
247
+ name: "log_entry",
248
+ indexes: [
249
+ { name: "id", algorithm: "btree", columns: [
250
+ "id"
251
+ ] }
252
+ ],
253
+ constraints: [
254
+ { name: "log_entry_id_key", constraint: "unique", columns: ["id"] }
255
+ ]
256
+ }, log_entry_table_default)
257
+ });
258
+ var reducersSchema = __reducers(__reducerSchema("add_log", add_log_reducer_default), __reducerSchema("add_logs_batch", add_logs_batch_reducer_default), __reducerSchema("check_timeouts", check_timeouts_reducer_default), __reducerSchema("create_root_flow", create_root_flow_reducer_default), __reducerSchema("create_sub_flow", create_sub_flow_reducer_default), __reducerSchema("finish_action", finish_action_reducer_default), __reducerSchema("finish_flow", finish_flow_reducer_default), __reducerSchema("register_key", register_key_reducer_default), __reducerSchema("start_action", start_action_reducer_default), __reducerSchema("update_error_group_status", update_error_group_status_reducer_default));
259
+ var proceduresSchema = __procedures();
260
+ var REMOTE_MODULE = {
261
+ versionInfo: {
262
+ cliVersion: "2.0.3"
263
+ },
264
+ tables: tablesSchema.schemaType.tables,
265
+ reducers: reducersSchema.reducersType.reducers,
266
+ ...proceduresSchema
267
+ };
268
+ var tables = __makeQueryBuilder(tablesSchema.schemaType);
269
+ var reducers = __convertToAccessorMap(reducersSchema.reducersType.reducers);
270
+
271
+ class SubscriptionBuilder extends __SubscriptionBuilderImpl {
272
+ }
273
+
274
+ class DbConnectionBuilder extends __DbConnectionBuilder {
275
+ }
276
+
277
+ class DbConnection extends __DbConnectionImpl {
278
+ static builder = () => {
279
+ return new DbConnectionBuilder(REMOTE_MODULE, (config) => new DbConnection(config));
280
+ };
281
+ subscriptionBuilder = () => {
282
+ return new SubscriptionBuilder(this);
283
+ };
284
+ }
285
+
286
+ // src/connection.ts
287
+ class SdkConnection {
288
+ _host;
289
+ _dbName;
290
+ _conn = null;
291
+ _connectPromise = null;
292
+ _timeoutInterval = null;
293
+ _keyHash = null;
294
+ _flowWaiters = new Map;
295
+ constructor(host, dbName) {
296
+ this._host = host;
297
+ this._dbName = dbName;
298
+ }
299
+ setKeyHash(keyHash) {
300
+ this._keyHash = keyHash;
301
+ }
302
+ async connect() {
303
+ if (this._conn)
304
+ return this._conn;
305
+ if (this._connectPromise)
306
+ return this._connectPromise;
307
+ this._connectPromise = new Promise((resolve, reject) => {
308
+ const conn = DbConnection.builder().withUri(this._host).withDatabaseName(this._dbName).onConnect((c, _identity, _token) => {
309
+ this._conn = c;
310
+ c.subscriptionBuilder().onApplied(() => {
311
+ resolve(c);
312
+ }).subscribeToAllTables();
313
+ this._timeoutInterval = setInterval(() => {
314
+ if (this._keyHash) {
315
+ c.reducers.checkTimeouts({ keyHash: this._keyHash });
316
+ }
317
+ }, 30000);
318
+ }).onConnectError((_ctx, err) => {
319
+ reject(new Error(`SpacetimeDB connection failed: ${err}`));
320
+ }).build();
321
+ });
322
+ return this._connectPromise;
323
+ }
324
+ get conn() {
325
+ if (!this._conn)
326
+ throw new Error("Not connected");
327
+ return this._conn;
328
+ }
329
+ async createFlowAndResolveId(reducerCall, exportToken) {
330
+ const conn = this.conn;
331
+ for (const f of conn.db.flow.iter()) {
332
+ if (f.exportToken === exportToken)
333
+ return f.id;
334
+ }
335
+ return new Promise((resolve) => {
336
+ this._flowWaiters.set(exportToken, resolve);
337
+ reducerCall();
338
+ const check = () => {
339
+ for (const f of conn.db.flow.iter()) {
340
+ if (f.exportToken === exportToken) {
341
+ this._flowWaiters.delete(exportToken);
342
+ resolve(f.id);
343
+ return true;
344
+ }
345
+ }
346
+ return false;
347
+ };
348
+ let attempts = 0;
349
+ const interval = setInterval(() => {
350
+ if (check() || attempts++ > 100) {
351
+ clearInterval(interval);
352
+ if (attempts > 100) {
353
+ this._flowWaiters.delete(exportToken);
354
+ throw new Error(`Flow creation timed out for token ${exportToken}`);
355
+ }
356
+ }
357
+ }, 100);
358
+ });
359
+ }
360
+ disconnect() {
361
+ if (this._timeoutInterval) {
362
+ clearInterval(this._timeoutInterval);
363
+ this._timeoutInterval = null;
364
+ }
365
+ if (this._conn) {
366
+ this._conn.disconnect();
367
+ this._conn = null;
368
+ }
369
+ }
370
+ }
371
+
372
+ // src/index.ts
373
+ var _origConsole = {
374
+ log: console.log,
375
+ info: console.info,
376
+ warn: console.warn,
377
+ error: console.error,
378
+ debug: console.debug
379
+ };
380
+ var _flowStack = [];
381
+ function _patchConsole() {
382
+ const capture = (level) => (...args) => {
383
+ const flow = _flowStack[_flowStack.length - 1];
384
+ if (flow) {
385
+ const msg = args.map((a) => {
386
+ if (typeof a === "string")
387
+ return a;
388
+ if (a instanceof Error)
389
+ return a.message;
390
+ try {
391
+ return JSON.stringify(a);
392
+ } catch {
393
+ return String(a);
394
+ }
395
+ }).join(" ");
396
+ const data = args.length <= 1 ? undefined : args.length === 2 ? args[1] : args.slice(1);
397
+ flow.log(msg, data, level);
398
+ }
399
+ _origConsole[level === "info" ? "log" : level](...args);
400
+ };
401
+ console.log = capture("info");
402
+ console.info = capture("info");
403
+ console.warn = capture("warn");
404
+ console.error = capture("error");
405
+ console.debug = capture("debug");
406
+ }
407
+ function _restoreConsole() {
408
+ console.log = _origConsole.log;
409
+ console.info = _origConsole.info;
410
+ console.warn = _origConsole.warn;
411
+ console.error = _origConsole.error;
412
+ console.debug = _origConsole.debug;
413
+ }
414
+ function serialize(value) {
415
+ if (value === undefined || value === null)
416
+ return "{}";
417
+ if (value instanceof Error)
418
+ return JSON.stringify({
419
+ name: value.name,
420
+ message: value.message,
421
+ stack: value.stack
422
+ });
423
+ try {
424
+ return JSON.stringify(value, (_key, v) => typeof v === "bigint" ? v.toString() : v);
425
+ } catch {
426
+ return JSON.stringify({ value: String(value) });
427
+ }
428
+ }
429
+ async function hashKey(secretKey) {
430
+ const encoder = new TextEncoder;
431
+ const data = encoder.encode(secretKey);
432
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
433
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
434
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
435
+ }
436
+ function generateToken() {
437
+ const bytes = new Uint8Array(16);
438
+ crypto.getRandomValues(bytes);
439
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
440
+ }
441
+
442
+ class Flow {
443
+ _sdk;
444
+ _keyHash;
445
+ _id = null;
446
+ _exportToken;
447
+ _ready;
448
+ _resolveReady;
449
+ _pendingLogs = [];
450
+ _flushScheduled = false;
451
+ _isReady = false;
452
+ _finished = false;
453
+ _parentId;
454
+ _name;
455
+ _timeoutSeconds;
456
+ _release;
457
+ constructor(sdk, keyHash, parentId, name, timeoutSeconds, release = "") {
458
+ this._sdk = sdk;
459
+ this._keyHash = keyHash;
460
+ this._parentId = parentId;
461
+ this._name = name;
462
+ this._timeoutSeconds = !timeoutSeconds || timeoutSeconds === Infinity ? 0n : BigInt(timeoutSeconds);
463
+ this._release = release;
464
+ this._exportToken = generateToken();
465
+ this._ready = new Promise((resolve) => {
466
+ this._resolveReady = resolve;
467
+ });
468
+ }
469
+ async _create() {
470
+ const conn = this._sdk.conn;
471
+ const exportToken = this._exportToken;
472
+ const keyHash = this._keyHash;
473
+ const timeoutSeconds = this._timeoutSeconds;
474
+ if (this._parentId === 0n) {
475
+ const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createRootFlow({ keyHash, timeoutSeconds, exportToken, release: this._release }), exportToken);
476
+ this._id = id;
477
+ } else {
478
+ const parentFlowId = this._parentId;
479
+ const name = this._name;
480
+ const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createSubFlow({
481
+ keyHash,
482
+ parentFlowId,
483
+ name,
484
+ timeoutSeconds,
485
+ exportToken
486
+ }), exportToken);
487
+ this._id = id;
488
+ }
489
+ this._isReady = true;
490
+ this._resolveReady();
491
+ this._drain();
492
+ }
493
+ static MAX_PENDING = 1e4;
494
+ log(message, data, level = "info") {
495
+ if (this._finished) {
496
+ console.warn(`[radish] Cannot log to finished flow`);
497
+ return this;
498
+ }
499
+ if (this._pendingLogs.length >= Flow.MAX_PENDING) {
500
+ const dropped = this._pendingLogs.length - Flow.MAX_PENDING + 1;
501
+ this._pendingLogs.splice(0, dropped);
502
+ }
503
+ this._pendingLogs.push({
504
+ level,
505
+ message,
506
+ data: data !== undefined ? serialize(data) : "{}"
507
+ });
508
+ this._scheduleFlush();
509
+ return this;
510
+ }
511
+ info(message, data) {
512
+ return this.log(message, data, "info");
513
+ }
514
+ warn(message, data) {
515
+ return this.log(message, data, "warn");
516
+ }
517
+ error(message, data) {
518
+ return this.log(message, data, "error");
519
+ }
520
+ debug(message, data) {
521
+ return this.log(message, data, "debug");
522
+ }
523
+ action(name, timeoutSeconds = 100) {
524
+ const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release);
525
+ this._ready.then(() => {
526
+ child._parentId = this._id;
527
+ child._create();
528
+ });
529
+ return child;
530
+ }
531
+ flow(name, timeoutSeconds = 100) {
532
+ return this.action(name, timeoutSeconds);
533
+ }
534
+ async a(name, fn, timeoutSeconds = 100) {
535
+ const child = this.action(name, timeoutSeconds);
536
+ _flowStack.push(child);
537
+ _patchConsole();
538
+ try {
539
+ const result = await fn(child);
540
+ await child.finish();
541
+ return result;
542
+ } catch (e) {
543
+ await child.finishWithError(e instanceof Error ? e : String(e));
544
+ throw e;
545
+ } finally {
546
+ _flowStack.pop();
547
+ if (_flowStack.length === 0)
548
+ _restoreConsole();
549
+ }
550
+ }
551
+ async finish() {
552
+ await this._ready;
553
+ this._drain();
554
+ this._finished = true;
555
+ this._sdk.conn.reducers.finishFlow({
556
+ keyHash: this._keyHash,
557
+ flowId: this._id,
558
+ status: "finished",
559
+ errorMessage: ""
560
+ });
561
+ }
562
+ async finishWithError(err) {
563
+ const errorMessage = err ? typeof err === "string" ? err : err.message : "";
564
+ if (err) {
565
+ this.error(errorMessage, err);
566
+ }
567
+ await this._ready;
568
+ this._drain();
569
+ this._finished = true;
570
+ this._sdk.conn.reducers.finishFlow({
571
+ keyHash: this._keyHash,
572
+ flowId: this._id,
573
+ status: "error",
574
+ errorMessage
575
+ });
576
+ }
577
+ async exportID() {
578
+ await this._ready;
579
+ return JSON.stringify({
580
+ flowId: this._id.toString(),
581
+ exportToken: this._exportToken,
582
+ keyHash: this._keyHash
583
+ });
584
+ }
585
+ async getId() {
586
+ await this._ready;
587
+ return this._id;
588
+ }
589
+ disconnect() {
590
+ this._sdk.disconnect();
591
+ }
592
+ async finishAndDisconnect() {
593
+ await this.finish();
594
+ await new Promise((r) => setTimeout(r, 100));
595
+ this.disconnect();
596
+ }
597
+ _scheduleFlush() {
598
+ if (this._flushScheduled)
599
+ return;
600
+ this._flushScheduled = true;
601
+ queueMicrotask(() => {
602
+ this._flushScheduled = false;
603
+ this._drain();
604
+ });
605
+ }
606
+ _drain() {
607
+ if (!this._isReady || this._pendingLogs.length === 0)
608
+ return;
609
+ const batch = this._pendingLogs.splice(0);
610
+ const conn = this._sdk.conn;
611
+ if (batch.length === 1) {
612
+ const e = batch[0];
613
+ conn.reducers.addLog({
614
+ keyHash: this._keyHash,
615
+ flowId: this._id,
616
+ level: e.level,
617
+ message: e.message,
618
+ data: e.data
619
+ });
620
+ } else {
621
+ conn.reducers.addLogsBatch({
622
+ keyHash: this._keyHash,
623
+ flowId: this._id,
624
+ entries: JSON.stringify(batch)
625
+ });
626
+ }
627
+ }
628
+ }
629
+ function parseRetention(retention) {
630
+ const match = retention.match(/^(\d+)d$/);
631
+ if (!match)
632
+ throw new Error('Invalid retention format. Use e.g. "30d"');
633
+ return parseInt(match[1], 10);
634
+ }
635
+ async function RL(secretKey, options = {}) {
636
+ const {
637
+ host = "wss://maincloud.spacetimedb.com",
638
+ dbName = "radish-log",
639
+ label = "",
640
+ defaultTimeout = 100,
641
+ release = "",
642
+ retention = "30d"
643
+ } = options;
644
+ const retentionDays = parseRetention(retention);
645
+ const keyHash = await hashKey(secretKey);
646
+ const sdk = new SdkConnection(host, dbName);
647
+ sdk.setKeyHash(keyHash);
648
+ try {
649
+ await sdk.connect();
650
+ } catch (e) {
651
+ throw new Error(`Failed to connect to Radish (${host}/${dbName}): ${e instanceof Error ? e.message : e}`);
652
+ }
653
+ try {
654
+ sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
655
+ } catch {}
656
+ try {
657
+ sdk.conn.reducers.checkTimeouts({ keyHash });
658
+ } catch {}
659
+ const root = new Flow(sdk, keyHash, 0n, "/", 0, release);
660
+ root._create();
661
+ return root;
662
+ }
663
+ async function restoreFlow(secretKey, exportedId, options = {}) {
664
+ const { host = "wss://maincloud.spacetimedb.com", dbName = "radish-log" } = options;
665
+ const parsed = JSON.parse(exportedId);
666
+ const keyHash = await hashKey(secretKey);
667
+ if (keyHash !== parsed.keyHash) {
668
+ throw new Error("Secret key does not match the flow owner");
669
+ }
670
+ const sdk = new SdkConnection(host, dbName);
671
+ await sdk.connect();
672
+ const flow = new Flow(sdk, keyHash, 0n, "restored", 100);
673
+ flow._id = BigInt(parsed.flowId);
674
+ flow._exportToken = parsed.exportToken;
675
+ flow._resolveReady();
676
+ return flow;
677
+ }
678
+ function generateKey() {
679
+ const bytes = new Uint8Array(32);
680
+ crypto.getRandomValues(bytes);
681
+ return "rl_" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
682
+ }
683
+ export {
684
+ restoreFlow,
685
+ generateKey,
686
+ RL,
687
+ Flow
688
+ };
@@ -0,0 +1,17 @@
1
+ declare const _default: import("spacetimedb").RowBuilder<{
2
+ id: import("spacetimedb").U64ColumnBuilder<{
3
+ isPrimaryKey: true;
4
+ }>;
5
+ flowId: import("spacetimedb").U64ColumnBuilder<{
6
+ name: "flow_id";
7
+ }>;
8
+ name: import("spacetimedb").StringBuilder;
9
+ status: import("spacetimedb").StringBuilder;
10
+ createdAt: import("spacetimedb").TimestampColumnBuilder<{
11
+ name: "created_at";
12
+ }>;
13
+ finishedAt: import("spacetimedb").U64ColumnBuilder<{
14
+ name: "finished_at";
15
+ }>;
16
+ }>;
17
+ export default _default;
@@ -0,0 +1,8 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ flowId: import("spacetimedb").U64Builder;
4
+ level: import("spacetimedb").StringBuilder;
5
+ message: import("spacetimedb").StringBuilder;
6
+ data: import("spacetimedb").StringBuilder;
7
+ };
8
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ flowId: import("spacetimedb").U64Builder;
4
+ entries: import("spacetimedb").StringBuilder;
5
+ };
6
+ export default _default;
@@ -0,0 +1,14 @@
1
+ declare const _default: import("spacetimedb").RowBuilder<{
2
+ keyHash: import("spacetimedb").StringColumnBuilder<{
3
+ isPrimaryKey: true;
4
+ name: "key_hash";
5
+ }>;
6
+ label: import("spacetimedb").StringBuilder;
7
+ retentionDays: import("spacetimedb").U64ColumnBuilder<{
8
+ name: "retention_days";
9
+ }>;
10
+ createdAt: import("spacetimedb").TimestampColumnBuilder<{
11
+ name: "created_at";
12
+ }>;
13
+ }>;
14
+ export default _default;
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ };
4
+ export default _default;
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ timeoutSeconds: import("spacetimedb").U64Builder;
4
+ exportToken: import("spacetimedb").StringBuilder;
5
+ release: import("spacetimedb").StringBuilder;
6
+ };
7
+ export default _default;
@@ -0,0 +1,8 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ parentFlowId: import("spacetimedb").U64Builder;
4
+ name: import("spacetimedb").StringBuilder;
5
+ timeoutSeconds: import("spacetimedb").U64Builder;
6
+ exportToken: import("spacetimedb").StringBuilder;
7
+ };
8
+ export default _default;
@@ -0,0 +1,24 @@
1
+ declare const _default: import("spacetimedb").RowBuilder<{
2
+ id: import("spacetimedb").U64ColumnBuilder<{
3
+ isPrimaryKey: true;
4
+ }>;
5
+ keyHash: import("spacetimedb").StringColumnBuilder<{
6
+ name: "key_hash";
7
+ }>;
8
+ fingerprint: import("spacetimedb").StringBuilder;
9
+ message: import("spacetimedb").StringBuilder;
10
+ path: import("spacetimedb").StringBuilder;
11
+ release: import("spacetimedb").StringBuilder;
12
+ count: import("spacetimedb").U64Builder;
13
+ status: import("spacetimedb").StringBuilder;
14
+ firstSeenAt: import("spacetimedb").TimestampColumnBuilder<{
15
+ name: "first_seen_at";
16
+ }>;
17
+ lastSeenAt: import("spacetimedb").U64ColumnBuilder<{
18
+ name: "last_seen_at";
19
+ }>;
20
+ lastFlowId: import("spacetimedb").U64ColumnBuilder<{
21
+ name: "last_flow_id";
22
+ }>;
23
+ }>;
24
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ actionId: import("spacetimedb").U64Builder;
4
+ status: import("spacetimedb").StringBuilder;
5
+ };
6
+ export default _default;
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ flowId: import("spacetimedb").U64Builder;
4
+ status: import("spacetimedb").StringBuilder;
5
+ errorMessage: import("spacetimedb").StringBuilder;
6
+ };
7
+ export default _default;
@@ -0,0 +1,28 @@
1
+ declare const _default: import("spacetimedb").RowBuilder<{
2
+ id: import("spacetimedb").U64ColumnBuilder<{
3
+ isPrimaryKey: true;
4
+ }>;
5
+ keyHash: import("spacetimedb").StringColumnBuilder<{
6
+ name: "key_hash";
7
+ }>;
8
+ parentFlowId: import("spacetimedb").U64ColumnBuilder<{
9
+ name: "parent_flow_id";
10
+ }>;
11
+ name: import("spacetimedb").StringBuilder;
12
+ path: import("spacetimedb").StringBuilder;
13
+ status: import("spacetimedb").StringBuilder;
14
+ release: import("spacetimedb").StringBuilder;
15
+ timeoutSeconds: import("spacetimedb").U64ColumnBuilder<{
16
+ name: "timeout_seconds";
17
+ }>;
18
+ createdAt: import("spacetimedb").TimestampColumnBuilder<{
19
+ name: "created_at";
20
+ }>;
21
+ finishedAt: import("spacetimedb").U64ColumnBuilder<{
22
+ name: "finished_at";
23
+ }>;
24
+ exportToken: import("spacetimedb").StringColumnBuilder<{
25
+ name: "export_token";
26
+ }>;
27
+ }>;
28
+ export default _default;
@@ -0,0 +1,15 @@
1
+ declare const _default: import("spacetimedb").RowBuilder<{
2
+ id: import("spacetimedb").U64ColumnBuilder<{
3
+ isPrimaryKey: true;
4
+ }>;
5
+ flowId: import("spacetimedb").U64ColumnBuilder<{
6
+ name: "flow_id";
7
+ }>;
8
+ level: import("spacetimedb").StringBuilder;
9
+ message: import("spacetimedb").StringBuilder;
10
+ data: import("spacetimedb").StringBuilder;
11
+ createdAt: import("spacetimedb").TimestampColumnBuilder<{
12
+ name: "created_at";
13
+ }>;
14
+ }>;
15
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ label: import("spacetimedb").StringBuilder;
4
+ retentionDays: import("spacetimedb").U64Builder;
5
+ };
6
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ flowId: import("spacetimedb").U64Builder;
4
+ name: import("spacetimedb").StringBuilder;
5
+ };
6
+ export default _default;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import { type Infer as __Infer } from "spacetimedb";
2
+ import AddLogReducer from "../add_log_reducer";
3
+ import AddLogsBatchReducer from "../add_logs_batch_reducer";
4
+ import CheckTimeoutsReducer from "../check_timeouts_reducer";
5
+ import CreateRootFlowReducer from "../create_root_flow_reducer";
6
+ import CreateSubFlowReducer from "../create_sub_flow_reducer";
7
+ import FinishActionReducer from "../finish_action_reducer";
8
+ import FinishFlowReducer from "../finish_flow_reducer";
9
+ import RegisterKeyReducer from "../register_key_reducer";
10
+ import StartActionReducer from "../start_action_reducer";
11
+ import UpdateErrorGroupStatusReducer from "../update_error_group_status_reducer";
12
+ export type AddLogParams = __Infer<typeof AddLogReducer>;
13
+ export type AddLogsBatchParams = __Infer<typeof AddLogsBatchReducer>;
14
+ export type CheckTimeoutsParams = __Infer<typeof CheckTimeoutsReducer>;
15
+ export type CreateRootFlowParams = __Infer<typeof CreateRootFlowReducer>;
16
+ export type CreateSubFlowParams = __Infer<typeof CreateSubFlowReducer>;
17
+ export type FinishActionParams = __Infer<typeof FinishActionReducer>;
18
+ export type FinishFlowParams = __Infer<typeof FinishFlowReducer>;
19
+ export type RegisterKeyParams = __Infer<typeof RegisterKeyReducer>;
20
+ export type StartActionParams = __Infer<typeof StartActionReducer>;
21
+ export type UpdateErrorGroupStatusParams = __Infer<typeof UpdateErrorGroupStatusReducer>;
@@ -0,0 +1,59 @@
1
+ import { type Infer as __Infer } from "spacetimedb";
2
+ export declare const Action: import("spacetimedb").ProductBuilder<{
3
+ id: import("spacetimedb").U64Builder;
4
+ flowId: import("spacetimedb").U64Builder;
5
+ name: import("spacetimedb").StringBuilder;
6
+ status: import("spacetimedb").StringBuilder;
7
+ createdAt: import("spacetimedb").TimestampBuilder;
8
+ finishedAt: import("spacetimedb").U64Builder;
9
+ }>;
10
+ export type Action = __Infer<typeof Action>;
11
+ export declare const ApiKey: import("spacetimedb").ProductBuilder<{
12
+ keyHash: import("spacetimedb").StringBuilder;
13
+ label: import("spacetimedb").StringBuilder;
14
+ retentionDays: import("spacetimedb").U64Builder;
15
+ createdAt: import("spacetimedb").TimestampBuilder;
16
+ }>;
17
+ export type ApiKey = __Infer<typeof ApiKey>;
18
+ export declare const ErrorGroup: import("spacetimedb").ProductBuilder<{
19
+ id: import("spacetimedb").U64Builder;
20
+ keyHash: import("spacetimedb").StringBuilder;
21
+ fingerprint: import("spacetimedb").StringBuilder;
22
+ message: import("spacetimedb").StringBuilder;
23
+ path: import("spacetimedb").StringBuilder;
24
+ release: import("spacetimedb").StringBuilder;
25
+ count: import("spacetimedb").U64Builder;
26
+ status: import("spacetimedb").StringBuilder;
27
+ firstSeenAt: import("spacetimedb").TimestampBuilder;
28
+ lastSeenAt: import("spacetimedb").U64Builder;
29
+ lastFlowId: import("spacetimedb").U64Builder;
30
+ }>;
31
+ export type ErrorGroup = __Infer<typeof ErrorGroup>;
32
+ export declare const Flow: import("spacetimedb").ProductBuilder<{
33
+ id: import("spacetimedb").U64Builder;
34
+ keyHash: import("spacetimedb").StringBuilder;
35
+ parentFlowId: import("spacetimedb").U64Builder;
36
+ name: import("spacetimedb").StringBuilder;
37
+ path: import("spacetimedb").StringBuilder;
38
+ status: import("spacetimedb").StringBuilder;
39
+ release: import("spacetimedb").StringBuilder;
40
+ timeoutSeconds: import("spacetimedb").U64Builder;
41
+ createdAt: import("spacetimedb").TimestampBuilder;
42
+ finishedAt: import("spacetimedb").U64Builder;
43
+ exportToken: import("spacetimedb").StringBuilder;
44
+ }>;
45
+ export type Flow = __Infer<typeof Flow>;
46
+ export declare const GcJob: import("spacetimedb").ProductBuilder<{
47
+ scheduledId: import("spacetimedb").U64Builder;
48
+ scheduledAt: import("spacetimedb").ScheduleAtBuilder;
49
+ }>;
50
+ export type GcJob = __Infer<typeof GcJob>;
51
+ export declare const LogEntry: import("spacetimedb").ProductBuilder<{
52
+ id: import("spacetimedb").U64Builder;
53
+ flowId: import("spacetimedb").U64Builder;
54
+ level: import("spacetimedb").StringBuilder;
55
+ message: import("spacetimedb").StringBuilder;
56
+ data: import("spacetimedb").StringBuilder;
57
+ createdAt: import("spacetimedb").TimestampBuilder;
58
+ }>;
59
+ export type LogEntry = __Infer<typeof LogEntry>;
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ keyHash: import("spacetimedb").StringBuilder;
3
+ errorGroupId: import("spacetimedb").U64Builder;
4
+ status: import("spacetimedb").StringBuilder;
5
+ };
6
+ export default _default;
package/package.json CHANGED
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "name": "@radishbot/sdk",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
- "main": "src/index.ts",
6
- "types": "src/index.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "exports": {
8
- ".": "./src/index.ts"
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "bun": "./src/index.ts",
11
+ "default": "./dist/index.js"
12
+ }
9
13
  },
10
14
  "bin": {
11
15
  "radish": "./src/cli.ts"
12
16
  },
13
17
  "files": [
14
18
  "src",
19
+ "dist",
15
20
  "README.md"
16
21
  ],
17
22
  "scripts": {
23
+ "build": "bun build ./src/index.ts --outdir dist --target node --format esm --external spacetimedb --external ws",
24
+ "prepublishOnly": "bun run build",
18
25
  "cli": "bun run ./src/cli.ts"
19
26
  },
20
27
  "dependencies": {