@radishbot/sdk 0.4.0 → 0.6.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/README.md +35 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +106 -106
- package/package.json +1 -1
- package/src/cli.ts +43 -37
- package/src/connection.ts +5 -20
- package/src/index.ts +32 -11
- package/src/module_bindings/create_root_flow_reducer.ts +1 -0
- package/src/module_bindings/flow_table.ts +1 -0
- package/src/module_bindings/index.ts +0 -2
- package/src/module_bindings/types/reducers.ts +0 -2
- package/src/module_bindings/types.ts +7 -0
- package/src/module_bindings/check_timeouts_reducer.ts +0 -15
package/README.md
CHANGED
|
@@ -139,6 +139,34 @@ action.info("continuing from service B");
|
|
|
139
139
|
await action.finish();
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
## Run ID
|
|
143
|
+
|
|
144
|
+
Every `RL()` call auto-generates a **run ID** — a short random string that groups flows across processes. Pass it to subprocesses via env vars, CLI args, or message queues so all flows from one logical execution link together.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const root = await RL(key);
|
|
148
|
+
|
|
149
|
+
// Pass to subprocess
|
|
150
|
+
spawn("worker.ts", { env: { ...process.env, RADISH_RUN_ID: root.runId } });
|
|
151
|
+
|
|
152
|
+
// In the subprocess — same run ID groups them together
|
|
153
|
+
const worker = await RL(key, { runId: process.env.RADISH_RUN_ID });
|
|
154
|
+
worker.info("processing");
|
|
155
|
+
await worker.finishAndDisconnect();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
You can also generate a run ID upfront:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { generateRunId } from "@radishbot/sdk";
|
|
162
|
+
const runId = generateRunId();
|
|
163
|
+
// pass to multiple services
|
|
164
|
+
const a = await RL(key, { runId });
|
|
165
|
+
const b = await RL(key, { runId });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
In the dashboard, click a run ID badge to filter all flows from that run.
|
|
169
|
+
|
|
142
170
|
## Release Tracking
|
|
143
171
|
|
|
144
172
|
Tag every flow with a version or commit SHA. Errors are tracked per-release, and regressions (errors reappearing after being resolved) are detected automatically.
|
|
@@ -181,6 +209,7 @@ const root = await RL(key, {
|
|
|
181
209
|
defaultTimeout: 100, // seconds, default 100
|
|
182
210
|
release: "v1.0.0", // version or commit SHA
|
|
183
211
|
retention: "30d", // data retention period
|
|
212
|
+
runId: "abc123", // optional, auto-generated if omitted
|
|
184
213
|
});
|
|
185
214
|
```
|
|
186
215
|
|
|
@@ -204,12 +233,16 @@ Actions that exceed their timeout are automatically marked as timed out.
|
|
|
204
233
|
|
|
205
234
|
### `RL(secretKey, options?) → Promise<Flow>`
|
|
206
235
|
|
|
207
|
-
Connect and create a root action. Options: `host`, `dbName`, `defaultTimeout`, `release`, `retention`.
|
|
236
|
+
Connect and create a root action. Options: `host`, `dbName`, `defaultTimeout`, `release`, `retention`, `runId`.
|
|
208
237
|
|
|
209
238
|
### `generateKey() → string`
|
|
210
239
|
|
|
211
240
|
Generate a random secret key (prefix `rl_`).
|
|
212
241
|
|
|
242
|
+
### `generateRunId() → string`
|
|
243
|
+
|
|
244
|
+
Generate a random run ID. Useful when you want to create the ID before calling `RL()`.
|
|
245
|
+
|
|
213
246
|
### `restoreFlow(secretKey, handle, options?) → Promise<Flow>`
|
|
214
247
|
|
|
215
248
|
Restore an action from an exported handle string.
|
|
@@ -228,4 +261,5 @@ Restore an action from an exported handle string.
|
|
|
228
261
|
| `.debug(msg, data?)` | Log at debug level. |
|
|
229
262
|
| `.log(msg, data?, level?)` | Log at any level. |
|
|
230
263
|
| `.exportID()` | Export handle for cross-context restore. |
|
|
264
|
+
| `.runId` | The run ID (read-only). Pass to subprocesses. |
|
|
231
265
|
| `.getId()` | Get server-assigned action ID. |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type LogLevel = "info" | "warn" | "error" | "debug";
|
|
2
2
|
|
|
3
3
|
export declare class Flow {
|
|
4
|
+
readonly runId: string;
|
|
4
5
|
log(message: string, data?: unknown, level?: LogLevel): this;
|
|
5
6
|
info(message: string, data?: unknown): this;
|
|
6
7
|
warn(message: string, data?: unknown): this;
|
|
@@ -24,8 +25,10 @@ export interface RLOptions {
|
|
|
24
25
|
defaultTimeout?: number;
|
|
25
26
|
release?: string;
|
|
26
27
|
retention?: string;
|
|
28
|
+
runId?: string;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export declare function RL(secretKey: string, options?: RLOptions): Promise<Flow>;
|
|
30
32
|
export declare function restoreFlow(secretKey: string, exportedId: string, options?: RLOptions): Promise<Flow>;
|
|
31
33
|
export declare function generateKey(): string;
|
|
34
|
+
export declare function generateRunId(): string;
|
package/dist/index.js
CHANGED
|
@@ -34,159 +34,153 @@ var add_logs_batch_reducer_default = {
|
|
|
34
34
|
entries: __t2.string()
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
// src/module_bindings/
|
|
37
|
+
// src/module_bindings/create_root_flow_reducer.ts
|
|
38
38
|
import {
|
|
39
39
|
t as __t3
|
|
40
40
|
} from "spacetimedb";
|
|
41
|
-
var
|
|
42
|
-
keyHash: __t3.string()
|
|
41
|
+
var create_root_flow_reducer_default = {
|
|
42
|
+
keyHash: __t3.string(),
|
|
43
|
+
runId: __t3.string(),
|
|
44
|
+
timeoutSeconds: __t3.u64(),
|
|
45
|
+
exportToken: __t3.string(),
|
|
46
|
+
release: __t3.string()
|
|
43
47
|
};
|
|
44
48
|
|
|
45
|
-
// src/module_bindings/
|
|
49
|
+
// src/module_bindings/create_sub_flow_reducer.ts
|
|
46
50
|
import {
|
|
47
51
|
t as __t4
|
|
48
52
|
} from "spacetimedb";
|
|
49
|
-
var
|
|
53
|
+
var create_sub_flow_reducer_default = {
|
|
50
54
|
keyHash: __t4.string(),
|
|
55
|
+
parentFlowId: __t4.u64(),
|
|
56
|
+
name: __t4.string(),
|
|
51
57
|
timeoutSeconds: __t4.u64(),
|
|
52
|
-
exportToken: __t4.string()
|
|
53
|
-
release: __t4.string()
|
|
58
|
+
exportToken: __t4.string()
|
|
54
59
|
};
|
|
55
60
|
|
|
56
|
-
// src/module_bindings/
|
|
61
|
+
// src/module_bindings/finish_action_reducer.ts
|
|
57
62
|
import {
|
|
58
63
|
t as __t5
|
|
59
64
|
} from "spacetimedb";
|
|
60
|
-
var
|
|
65
|
+
var finish_action_reducer_default = {
|
|
61
66
|
keyHash: __t5.string(),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
timeoutSeconds: __t5.u64(),
|
|
65
|
-
exportToken: __t5.string()
|
|
67
|
+
actionId: __t5.u64(),
|
|
68
|
+
status: __t5.string()
|
|
66
69
|
};
|
|
67
70
|
|
|
68
|
-
// src/module_bindings/
|
|
71
|
+
// src/module_bindings/finish_flow_reducer.ts
|
|
69
72
|
import {
|
|
70
73
|
t as __t6
|
|
71
74
|
} from "spacetimedb";
|
|
72
|
-
var
|
|
75
|
+
var finish_flow_reducer_default = {
|
|
73
76
|
keyHash: __t6.string(),
|
|
74
|
-
|
|
75
|
-
status: __t6.string()
|
|
77
|
+
flowId: __t6.u64(),
|
|
78
|
+
status: __t6.string(),
|
|
79
|
+
errorMessage: __t6.string()
|
|
76
80
|
};
|
|
77
81
|
|
|
78
|
-
// src/module_bindings/
|
|
82
|
+
// src/module_bindings/register_key_reducer.ts
|
|
79
83
|
import {
|
|
80
84
|
t as __t7
|
|
81
85
|
} from "spacetimedb";
|
|
82
|
-
var
|
|
86
|
+
var register_key_reducer_default = {
|
|
83
87
|
keyHash: __t7.string(),
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
errorMessage: __t7.string()
|
|
88
|
+
label: __t7.string(),
|
|
89
|
+
retentionDays: __t7.u64()
|
|
87
90
|
};
|
|
88
91
|
|
|
89
|
-
// src/module_bindings/
|
|
92
|
+
// src/module_bindings/start_action_reducer.ts
|
|
90
93
|
import {
|
|
91
94
|
t as __t8
|
|
92
95
|
} from "spacetimedb";
|
|
93
|
-
var
|
|
96
|
+
var start_action_reducer_default = {
|
|
94
97
|
keyHash: __t8.string(),
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
flowId: __t8.u64(),
|
|
99
|
+
name: __t8.string()
|
|
97
100
|
};
|
|
98
101
|
|
|
99
|
-
// src/module_bindings/
|
|
102
|
+
// src/module_bindings/update_error_group_status_reducer.ts
|
|
100
103
|
import {
|
|
101
104
|
t as __t9
|
|
102
105
|
} from "spacetimedb";
|
|
103
|
-
var
|
|
106
|
+
var update_error_group_status_reducer_default = {
|
|
104
107
|
keyHash: __t9.string(),
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
errorGroupId: __t9.u64(),
|
|
109
|
+
status: __t9.string()
|
|
107
110
|
};
|
|
108
111
|
|
|
109
|
-
// src/module_bindings/
|
|
112
|
+
// src/module_bindings/action_table.ts
|
|
110
113
|
import {
|
|
111
114
|
t as __t10
|
|
112
115
|
} from "spacetimedb";
|
|
113
|
-
var
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
var action_table_default = __t10.row({
|
|
117
|
+
id: __t10.u64().primaryKey(),
|
|
118
|
+
flowId: __t10.u64().name("flow_id"),
|
|
119
|
+
name: __t10.string(),
|
|
120
|
+
status: __t10.string(),
|
|
121
|
+
createdAt: __t10.timestamp().name("created_at"),
|
|
122
|
+
finishedAt: __t10.u64().name("finished_at")
|
|
123
|
+
});
|
|
118
124
|
|
|
119
|
-
// src/module_bindings/
|
|
125
|
+
// src/module_bindings/api_key_table.ts
|
|
120
126
|
import {
|
|
121
127
|
t as __t11
|
|
122
128
|
} from "spacetimedb";
|
|
123
|
-
var
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
createdAt: __t11.timestamp().name("created_at"),
|
|
129
|
-
finishedAt: __t11.u64().name("finished_at")
|
|
129
|
+
var api_key_table_default = __t11.row({
|
|
130
|
+
keyHash: __t11.string().primaryKey().name("key_hash"),
|
|
131
|
+
label: __t11.string(),
|
|
132
|
+
retentionDays: __t11.u64().name("retention_days"),
|
|
133
|
+
createdAt: __t11.timestamp().name("created_at")
|
|
130
134
|
});
|
|
131
135
|
|
|
132
|
-
// src/module_bindings/
|
|
136
|
+
// src/module_bindings/error_group_table.ts
|
|
133
137
|
import {
|
|
134
138
|
t as __t12
|
|
135
139
|
} from "spacetimedb";
|
|
136
|
-
var
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
var error_group_table_default = __t12.row({
|
|
141
|
+
id: __t12.u64().primaryKey(),
|
|
142
|
+
keyHash: __t12.string().name("key_hash"),
|
|
143
|
+
fingerprint: __t12.string(),
|
|
144
|
+
message: __t12.string(),
|
|
145
|
+
path: __t12.string(),
|
|
146
|
+
release: __t12.string(),
|
|
147
|
+
count: __t12.u64(),
|
|
148
|
+
status: __t12.string(),
|
|
149
|
+
firstSeenAt: __t12.timestamp().name("first_seen_at"),
|
|
150
|
+
lastSeenAt: __t12.u64().name("last_seen_at"),
|
|
151
|
+
lastFlowId: __t12.u64().name("last_flow_id")
|
|
141
152
|
});
|
|
142
153
|
|
|
143
|
-
// src/module_bindings/
|
|
154
|
+
// src/module_bindings/flow_table.ts
|
|
144
155
|
import {
|
|
145
156
|
t as __t13
|
|
146
157
|
} from "spacetimedb";
|
|
147
|
-
var
|
|
158
|
+
var flow_table_default = __t13.row({
|
|
148
159
|
id: __t13.u64().primaryKey(),
|
|
149
160
|
keyHash: __t13.string().name("key_hash"),
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
runId: __t13.string().name("run_id"),
|
|
162
|
+
parentFlowId: __t13.u64().name("parent_flow_id"),
|
|
163
|
+
name: __t13.string(),
|
|
152
164
|
path: __t13.string(),
|
|
153
|
-
release: __t13.string(),
|
|
154
|
-
count: __t13.u64(),
|
|
155
165
|
status: __t13.string(),
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
166
|
+
release: __t13.string(),
|
|
167
|
+
timeoutSeconds: __t13.u64().name("timeout_seconds"),
|
|
168
|
+
createdAt: __t13.timestamp().name("created_at"),
|
|
169
|
+
finishedAt: __t13.u64().name("finished_at"),
|
|
170
|
+
exportToken: __t13.string().name("export_token")
|
|
159
171
|
});
|
|
160
172
|
|
|
161
|
-
// src/module_bindings/
|
|
173
|
+
// src/module_bindings/log_entry_table.ts
|
|
162
174
|
import {
|
|
163
175
|
t as __t14
|
|
164
176
|
} from "spacetimedb";
|
|
165
|
-
var
|
|
177
|
+
var log_entry_table_default = __t14.row({
|
|
166
178
|
id: __t14.u64().primaryKey(),
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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")
|
|
179
|
+
flowId: __t14.u64().name("flow_id"),
|
|
180
|
+
level: __t14.string(),
|
|
181
|
+
message: __t14.string(),
|
|
182
|
+
data: __t14.string(),
|
|
183
|
+
createdAt: __t14.timestamp().name("created_at")
|
|
190
184
|
});
|
|
191
185
|
|
|
192
186
|
// src/module_bindings/index.ts
|
|
@@ -255,7 +249,7 @@ var tablesSchema = __schema({
|
|
|
255
249
|
]
|
|
256
250
|
}, log_entry_table_default)
|
|
257
251
|
});
|
|
258
|
-
var reducersSchema = __reducers(__reducerSchema("add_log", add_log_reducer_default), __reducerSchema("add_logs_batch", add_logs_batch_reducer_default), __reducerSchema("
|
|
252
|
+
var reducersSchema = __reducers(__reducerSchema("add_log", add_log_reducer_default), __reducerSchema("add_logs_batch", add_logs_batch_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
253
|
var proceduresSchema = __procedures();
|
|
260
254
|
var REMOTE_MODULE = {
|
|
261
255
|
versionInfo: {
|
|
@@ -289,7 +283,6 @@ class SdkConnection {
|
|
|
289
283
|
_dbName;
|
|
290
284
|
_conn = null;
|
|
291
285
|
_connectPromise = null;
|
|
292
|
-
_timeoutInterval = null;
|
|
293
286
|
_keyHash = null;
|
|
294
287
|
_flowWaiters = new Map;
|
|
295
288
|
constructor(host, dbName) {
|
|
@@ -309,12 +302,7 @@ class SdkConnection {
|
|
|
309
302
|
this._conn = c;
|
|
310
303
|
c.subscriptionBuilder().onApplied(() => {
|
|
311
304
|
resolve(c);
|
|
312
|
-
}).
|
|
313
|
-
this._timeoutInterval = setInterval(() => {
|
|
314
|
-
if (this._keyHash) {
|
|
315
|
-
c.reducers.checkTimeouts({ keyHash: this._keyHash });
|
|
316
|
-
}
|
|
317
|
-
}, 30000);
|
|
305
|
+
}).subscribe([`SELECT * FROM flow WHERE key_hash = '${this._keyHash}'`]);
|
|
318
306
|
}).onConnectError((_ctx, err) => {
|
|
319
307
|
reject(new Error(`SpacetimeDB connection failed: ${err}`));
|
|
320
308
|
}).build();
|
|
@@ -358,10 +346,6 @@ class SdkConnection {
|
|
|
358
346
|
});
|
|
359
347
|
}
|
|
360
348
|
disconnect() {
|
|
361
|
-
if (this._timeoutInterval) {
|
|
362
|
-
clearInterval(this._timeoutInterval);
|
|
363
|
-
this._timeoutInterval = null;
|
|
364
|
-
}
|
|
365
349
|
if (this._conn) {
|
|
366
350
|
this._conn.disconnect();
|
|
367
351
|
this._conn = null;
|
|
@@ -454,13 +438,15 @@ class Flow {
|
|
|
454
438
|
_name;
|
|
455
439
|
_timeoutSeconds;
|
|
456
440
|
_release;
|
|
457
|
-
|
|
441
|
+
_runId;
|
|
442
|
+
constructor(sdk, keyHash, parentId, name, timeoutSeconds, release = "", runId = "") {
|
|
458
443
|
this._sdk = sdk;
|
|
459
444
|
this._keyHash = keyHash;
|
|
460
445
|
this._parentId = parentId;
|
|
461
446
|
this._name = name;
|
|
462
447
|
this._timeoutSeconds = !timeoutSeconds || timeoutSeconds === Infinity ? 0n : BigInt(timeoutSeconds);
|
|
463
448
|
this._release = release;
|
|
449
|
+
this._runId = runId;
|
|
464
450
|
this._exportToken = generateToken();
|
|
465
451
|
this._ready = new Promise((resolve) => {
|
|
466
452
|
this._resolveReady = resolve;
|
|
@@ -472,7 +458,13 @@ class Flow {
|
|
|
472
458
|
const keyHash = this._keyHash;
|
|
473
459
|
const timeoutSeconds = this._timeoutSeconds;
|
|
474
460
|
if (this._parentId === 0n) {
|
|
475
|
-
const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createRootFlow({
|
|
461
|
+
const id = await this._sdk.createFlowAndResolveId(() => conn.reducers.createRootFlow({
|
|
462
|
+
keyHash,
|
|
463
|
+
runId: this._runId,
|
|
464
|
+
timeoutSeconds,
|
|
465
|
+
exportToken,
|
|
466
|
+
release: this._release
|
|
467
|
+
}), exportToken);
|
|
476
468
|
this._id = id;
|
|
477
469
|
} else {
|
|
478
470
|
const parentFlowId = this._parentId;
|
|
@@ -521,7 +513,7 @@ class Flow {
|
|
|
521
513
|
return this.log(message, data, "debug");
|
|
522
514
|
}
|
|
523
515
|
action(name, timeoutSeconds = 100) {
|
|
524
|
-
const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release);
|
|
516
|
+
const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release, this._runId);
|
|
525
517
|
this._ready.then(() => {
|
|
526
518
|
child._parentId = this._id;
|
|
527
519
|
child._create();
|
|
@@ -574,12 +566,16 @@ class Flow {
|
|
|
574
566
|
errorMessage
|
|
575
567
|
});
|
|
576
568
|
}
|
|
569
|
+
get runId() {
|
|
570
|
+
return this._runId;
|
|
571
|
+
}
|
|
577
572
|
async exportID() {
|
|
578
573
|
await this._ready;
|
|
579
574
|
return JSON.stringify({
|
|
580
575
|
flowId: this._id.toString(),
|
|
581
576
|
exportToken: this._exportToken,
|
|
582
|
-
keyHash: this._keyHash
|
|
577
|
+
keyHash: this._keyHash,
|
|
578
|
+
runId: this._runId
|
|
583
579
|
});
|
|
584
580
|
}
|
|
585
581
|
async getId() {
|
|
@@ -639,7 +635,8 @@ async function RL(secretKey, options = {}) {
|
|
|
639
635
|
label = "",
|
|
640
636
|
defaultTimeout = 100,
|
|
641
637
|
release = "",
|
|
642
|
-
retention = "30d"
|
|
638
|
+
retention = "30d",
|
|
639
|
+
runId = generateRunId()
|
|
643
640
|
} = options;
|
|
644
641
|
const retentionDays = parseRetention(retention);
|
|
645
642
|
const keyHash = await hashKey(secretKey);
|
|
@@ -653,10 +650,7 @@ async function RL(secretKey, options = {}) {
|
|
|
653
650
|
try {
|
|
654
651
|
sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
|
|
655
652
|
} catch {}
|
|
656
|
-
|
|
657
|
-
sdk.conn.reducers.checkTimeouts({ keyHash });
|
|
658
|
-
} catch {}
|
|
659
|
-
const root = new Flow(sdk, keyHash, 0n, "/", 0, release);
|
|
653
|
+
const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
|
|
660
654
|
root._create();
|
|
661
655
|
return root;
|
|
662
656
|
}
|
|
@@ -669,7 +663,7 @@ async function restoreFlow(secretKey, exportedId, options = {}) {
|
|
|
669
663
|
}
|
|
670
664
|
const sdk = new SdkConnection(host, dbName);
|
|
671
665
|
await sdk.connect();
|
|
672
|
-
const flow = new Flow(sdk, keyHash, 0n, "restored", 100);
|
|
666
|
+
const flow = new Flow(sdk, keyHash, 0n, "restored", 100, "", parsed.runId || "");
|
|
673
667
|
flow._id = BigInt(parsed.flowId);
|
|
674
668
|
flow._exportToken = parsed.exportToken;
|
|
675
669
|
flow._resolveReady();
|
|
@@ -680,8 +674,14 @@ function generateKey() {
|
|
|
680
674
|
crypto.getRandomValues(bytes);
|
|
681
675
|
return "rl_" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
682
676
|
}
|
|
677
|
+
function generateRunId() {
|
|
678
|
+
const bytes = new Uint8Array(8);
|
|
679
|
+
crypto.getRandomValues(bytes);
|
|
680
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
681
|
+
}
|
|
683
682
|
export {
|
|
684
683
|
restoreFlow,
|
|
684
|
+
generateRunId,
|
|
685
685
|
generateKey,
|
|
686
686
|
RL,
|
|
687
687
|
Flow
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -144,24 +144,16 @@ function connect(
|
|
|
144
144
|
.onConnect((c, _identity, _token) => {
|
|
145
145
|
c.subscriptionBuilder()
|
|
146
146
|
.onApplied(() => {
|
|
147
|
-
const flows = () =>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return result;
|
|
151
|
-
};
|
|
152
|
-
const logs = () => {
|
|
153
|
-
const result: any[] = [];
|
|
154
|
-
for (const l of c.db.logEntry.iter()) result.push(l);
|
|
155
|
-
return result;
|
|
156
|
-
};
|
|
157
|
-
const errorGroups = () => {
|
|
158
|
-
const result: any[] = [];
|
|
159
|
-
for (const g of c.db.errorGroup.iter()) if (g.keyHash === keyHash) result.push(g);
|
|
160
|
-
return result;
|
|
161
|
-
};
|
|
147
|
+
const flows = () => [...c.db.flow.iter()];
|
|
148
|
+
const logs = () => [...c.db.logEntry.iter()];
|
|
149
|
+
const errorGroups = () => [...c.db.errorGroup.iter()];
|
|
162
150
|
resolve({ conn: c, flows, logs, errorGroups });
|
|
163
151
|
})
|
|
164
|
-
.
|
|
152
|
+
.subscribe([
|
|
153
|
+
`SELECT * FROM flow WHERE key_hash = '${keyHash}'`,
|
|
154
|
+
`SELECT * FROM log_entry WHERE flow_id IN (SELECT id FROM flow WHERE key_hash = '${keyHash}')`,
|
|
155
|
+
`SELECT * FROM error_group WHERE key_hash = '${keyHash}'`,
|
|
156
|
+
]);
|
|
165
157
|
})
|
|
166
158
|
.onConnectError((_ctx, err) => reject(new Error(`Connection failed: ${err}`)))
|
|
167
159
|
.build();
|
|
@@ -185,19 +177,27 @@ function cmdList(flows: any[]) {
|
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
const hasRelease = roots.some((f) => f.release && f.release !== "");
|
|
180
|
+
const hasRunId = roots.some((f) => f.runId && f.runId !== "");
|
|
188
181
|
|
|
189
182
|
console.log(`${c.bold}Flows${c.reset} ${c.dim}(${roots.length} total)${c.reset}\n`);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
183
|
+
const cols = [
|
|
184
|
+
"ID".padEnd(8),
|
|
185
|
+
"STATUS".padEnd(10),
|
|
186
|
+
...(hasRunId ? ["RUN".padEnd(18)] : []),
|
|
187
|
+
...(hasRelease ? ["RELEASE".padEnd(10)] : []),
|
|
188
|
+
"DURATION".padEnd(10),
|
|
189
|
+
"CREATED",
|
|
190
|
+
];
|
|
191
|
+
const divs = [
|
|
192
|
+
"─".repeat(8),
|
|
193
|
+
"─".repeat(10),
|
|
194
|
+
...(hasRunId ? ["─".repeat(18)] : []),
|
|
195
|
+
...(hasRelease ? ["─".repeat(10)] : []),
|
|
196
|
+
"─".repeat(10),
|
|
197
|
+
"─".repeat(24),
|
|
198
|
+
];
|
|
199
|
+
console.log(`${c.dim} ${cols.join(" ")}${c.reset}`);
|
|
200
|
+
console.log(`${c.dim} ${divs.join(" ")}${c.reset}`);
|
|
201
201
|
|
|
202
202
|
for (const f of roots.slice(0, 30)) {
|
|
203
203
|
const id = f.id.toString().padEnd(8);
|
|
@@ -205,8 +205,11 @@ function cmdList(flows: any[]) {
|
|
|
205
205
|
const status = padRight(f.status, 10);
|
|
206
206
|
const dur = f.finishedAt !== 0n ? padRight(fmtDuration(f.createdAt, f.finishedAt), 10) : padRight("—", 10);
|
|
207
207
|
const time = fmtDateTime(f.createdAt);
|
|
208
|
+
const runIdCol = hasRunId ? padRight(f.runId ? f.runId.slice(0, 16) : "—", 18) : "";
|
|
208
209
|
const release = hasRelease ? padRight(f.release || "—", 10) + " " : "";
|
|
209
|
-
console.log(
|
|
210
|
+
console.log(
|
|
211
|
+
` ${c.dim}${id}${c.reset} ${sc}${status}${c.reset} ${hasRunId ? runIdCol + " " : ""}${release}${dur} ${c.dim}${time}${c.reset}`,
|
|
212
|
+
);
|
|
210
213
|
}
|
|
211
214
|
|
|
212
215
|
if (roots.length > 30) {
|
|
@@ -225,6 +228,9 @@ function cmdShow(flowId: bigint, allFlows: any[], allLogs: any[]) {
|
|
|
225
228
|
const sc = statusColor(flow.status);
|
|
226
229
|
const releaseTag = flow.release ? ` ${c.dim}(${flow.release})${c.reset}` : "";
|
|
227
230
|
console.log(`${c.bold}Flow #${flow.id}${c.reset} ${sc}${flow.status}${c.reset}${releaseTag}`);
|
|
231
|
+
if (flow.runId) {
|
|
232
|
+
console.log(`${c.dim}Run: ${flow.runId}${c.reset}`);
|
|
233
|
+
}
|
|
228
234
|
console.log(`${c.dim}Created: ${fmtDateTime(flow.createdAt)}${c.reset}`);
|
|
229
235
|
if (flow.finishedAt !== 0n) {
|
|
230
236
|
console.log(`${c.dim}Duration: ${fmtDuration(flow.createdAt, flow.finishedAt)}${c.reset}`);
|
|
@@ -346,12 +352,15 @@ async function cmdTail(keyHash: string) {
|
|
|
346
352
|
.onApplied(() => {
|
|
347
353
|
// Seed known flows and seen logs
|
|
348
354
|
for (const f of c.db.flow.iter()) {
|
|
349
|
-
|
|
355
|
+
flowNames.set(f.id, f.name === "/" ? "root" : f.name);
|
|
350
356
|
}
|
|
351
357
|
for (const l of c.db.logEntry.iter()) seen.add(l.id);
|
|
352
358
|
resolve(c);
|
|
353
359
|
})
|
|
354
|
-
.
|
|
360
|
+
.subscribe([
|
|
361
|
+
`SELECT * FROM flow WHERE key_hash = '${keyHash}'`,
|
|
362
|
+
`SELECT * FROM log_entry WHERE flow_id IN (SELECT id FROM flow WHERE key_hash = '${keyHash}')`,
|
|
363
|
+
]);
|
|
355
364
|
})
|
|
356
365
|
.onConnectError((_ctx, err) => reject(new Error(`Connection failed: ${err}`)))
|
|
357
366
|
.build();
|
|
@@ -359,9 +368,9 @@ async function cmdTail(keyHash: string) {
|
|
|
359
368
|
|
|
360
369
|
// Poll for new logs
|
|
361
370
|
setInterval(() => {
|
|
362
|
-
// Update flow names
|
|
371
|
+
// Update flow names (subscription already filters by key)
|
|
363
372
|
for (const f of conn.db.flow.iter()) {
|
|
364
|
-
if (
|
|
373
|
+
if (!flowNames.has(f.id)) {
|
|
365
374
|
flowNames.set(f.id, f.name === "/" ? "root" : f.name);
|
|
366
375
|
}
|
|
367
376
|
}
|
|
@@ -369,11 +378,8 @@ async function cmdTail(keyHash: string) {
|
|
|
369
378
|
const newLogs: any[] = [];
|
|
370
379
|
for (const l of conn.db.logEntry.iter()) {
|
|
371
380
|
if (!seen.has(l.id) && l.level !== "flow" && l.level !== "action") {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
seen.add(l.id);
|
|
375
|
-
newLogs.push(l);
|
|
376
|
-
}
|
|
381
|
+
seen.add(l.id);
|
|
382
|
+
newLogs.push(l);
|
|
377
383
|
}
|
|
378
384
|
}
|
|
379
385
|
|
package/src/connection.ts
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* SpacetimeDB connection wrapper for the Radish SDK.
|
|
3
3
|
* Uses the generated bindings + SpacetimeDB WebSocket client.
|
|
4
4
|
*/
|
|
5
|
-
import { DbConnection as StdbConnection } from
|
|
5
|
+
import { DbConnection as StdbConnection } from "./module_bindings";
|
|
6
6
|
|
|
7
7
|
export class SdkConnection {
|
|
8
8
|
private _host: string;
|
|
9
9
|
private _dbName: string;
|
|
10
10
|
private _conn: StdbConnection | null = null;
|
|
11
11
|
private _connectPromise: Promise<StdbConnection> | null = null;
|
|
12
|
-
private _timeoutInterval: ReturnType<typeof setInterval> | null = null;
|
|
13
12
|
private _keyHash: string | null = null;
|
|
14
13
|
|
|
15
14
|
// Callbacks waiting for flow creation by exportToken
|
|
@@ -35,19 +34,12 @@ export class SdkConnection {
|
|
|
35
34
|
.onConnect((c, _identity, _token) => {
|
|
36
35
|
this._conn = c;
|
|
37
36
|
|
|
38
|
-
//
|
|
37
|
+
// Only subscribe to flows for this key (needed to resolve flow IDs)
|
|
39
38
|
c.subscriptionBuilder()
|
|
40
39
|
.onApplied(() => {
|
|
41
40
|
resolve(c);
|
|
42
41
|
})
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
// Periodic timeout check (every 30s)
|
|
46
|
-
this._timeoutInterval = setInterval(() => {
|
|
47
|
-
if (this._keyHash) {
|
|
48
|
-
c.reducers.checkTimeouts({ keyHash: this._keyHash });
|
|
49
|
-
}
|
|
50
|
-
}, 30_000);
|
|
42
|
+
.subscribe([`SELECT * FROM flow WHERE key_hash = '${this._keyHash}'`]);
|
|
51
43
|
})
|
|
52
44
|
.onConnectError((_ctx, err) => {
|
|
53
45
|
reject(new Error(`SpacetimeDB connection failed: ${err}`));
|
|
@@ -59,7 +51,7 @@ export class SdkConnection {
|
|
|
59
51
|
}
|
|
60
52
|
|
|
61
53
|
get conn(): StdbConnection {
|
|
62
|
-
if (!this._conn) throw new Error(
|
|
54
|
+
if (!this._conn) throw new Error("Not connected");
|
|
63
55
|
return this._conn;
|
|
64
56
|
}
|
|
65
57
|
|
|
@@ -67,10 +59,7 @@ export class SdkConnection {
|
|
|
67
59
|
* Call a reducer and wait for the flow to appear in the subscription.
|
|
68
60
|
* Returns the server-assigned flow ID.
|
|
69
61
|
*/
|
|
70
|
-
async createFlowAndResolveId(
|
|
71
|
-
reducerCall: () => void,
|
|
72
|
-
exportToken: string
|
|
73
|
-
): Promise<bigint> {
|
|
62
|
+
async createFlowAndResolveId(reducerCall: () => void, exportToken: string): Promise<bigint> {
|
|
74
63
|
const conn = this.conn;
|
|
75
64
|
|
|
76
65
|
// Check if flow already exists (from a previous subscription update)
|
|
@@ -112,10 +101,6 @@ export class SdkConnection {
|
|
|
112
101
|
}
|
|
113
102
|
|
|
114
103
|
disconnect(): void {
|
|
115
|
-
if (this._timeoutInterval) {
|
|
116
|
-
clearInterval(this._timeoutInterval);
|
|
117
|
-
this._timeoutInterval = null;
|
|
118
|
-
}
|
|
119
104
|
if (this._conn) {
|
|
120
105
|
this._conn.disconnect();
|
|
121
106
|
this._conn = null;
|
package/src/index.ts
CHANGED
|
@@ -97,6 +97,7 @@ export class Flow {
|
|
|
97
97
|
private _name: string;
|
|
98
98
|
private _timeoutSeconds: bigint;
|
|
99
99
|
private _release: string;
|
|
100
|
+
private _runId: string;
|
|
100
101
|
|
|
101
102
|
/** @internal */
|
|
102
103
|
constructor(
|
|
@@ -106,6 +107,7 @@ export class Flow {
|
|
|
106
107
|
name: string,
|
|
107
108
|
timeoutSeconds: number,
|
|
108
109
|
release: string = "",
|
|
110
|
+
runId: string = "",
|
|
109
111
|
) {
|
|
110
112
|
this._sdk = sdk;
|
|
111
113
|
this._keyHash = keyHash;
|
|
@@ -113,6 +115,7 @@ export class Flow {
|
|
|
113
115
|
this._name = name;
|
|
114
116
|
this._timeoutSeconds = !timeoutSeconds || timeoutSeconds === Infinity ? 0n : BigInt(timeoutSeconds);
|
|
115
117
|
this._release = release;
|
|
118
|
+
this._runId = runId;
|
|
116
119
|
this._exportToken = generateToken();
|
|
117
120
|
this._ready = new Promise<void>((resolve) => {
|
|
118
121
|
this._resolveReady = resolve;
|
|
@@ -128,7 +131,14 @@ export class Flow {
|
|
|
128
131
|
|
|
129
132
|
if (this._parentId === 0n) {
|
|
130
133
|
const id = await this._sdk.createFlowAndResolveId(
|
|
131
|
-
() =>
|
|
134
|
+
() =>
|
|
135
|
+
conn.reducers.createRootFlow({
|
|
136
|
+
keyHash,
|
|
137
|
+
runId: this._runId,
|
|
138
|
+
timeoutSeconds,
|
|
139
|
+
exportToken,
|
|
140
|
+
release: this._release,
|
|
141
|
+
}),
|
|
132
142
|
exportToken,
|
|
133
143
|
);
|
|
134
144
|
this._id = id;
|
|
@@ -191,7 +201,7 @@ export class Flow {
|
|
|
191
201
|
|
|
192
202
|
/** Create a sub-action. Returns immediately — creation runs in background. */
|
|
193
203
|
action(name: string, timeoutSeconds = 100): Flow {
|
|
194
|
-
const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release);
|
|
204
|
+
const child = new Flow(this._sdk, this._keyHash, 0n, name, timeoutSeconds, this._release, this._runId);
|
|
195
205
|
this._ready.then(() => {
|
|
196
206
|
(child as any)._parentId = this._id!;
|
|
197
207
|
child._create();
|
|
@@ -252,6 +262,11 @@ export class Flow {
|
|
|
252
262
|
});
|
|
253
263
|
}
|
|
254
264
|
|
|
265
|
+
/** Get the run ID for this flow (pass to subprocesses via env, args, etc.) */
|
|
266
|
+
get runId(): string {
|
|
267
|
+
return this._runId;
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
/** Export this flow's handle for restoration in another context */
|
|
256
271
|
async exportID(): Promise<string> {
|
|
257
272
|
await this._ready;
|
|
@@ -259,6 +274,7 @@ export class Flow {
|
|
|
259
274
|
flowId: this._id!.toString(),
|
|
260
275
|
exportToken: this._exportToken,
|
|
261
276
|
keyHash: this._keyHash,
|
|
277
|
+
runId: this._runId,
|
|
262
278
|
});
|
|
263
279
|
}
|
|
264
280
|
|
|
@@ -323,6 +339,8 @@ export interface RLOptions {
|
|
|
323
339
|
defaultTimeout?: number;
|
|
324
340
|
release?: string;
|
|
325
341
|
retention?: string;
|
|
342
|
+
/** Run ID — groups flows across processes. Auto-generated if not provided. */
|
|
343
|
+
runId?: string;
|
|
326
344
|
}
|
|
327
345
|
|
|
328
346
|
function parseRetention(retention: string): number {
|
|
@@ -360,6 +378,7 @@ export async function RL(secretKey: string, options: RLOptions = {}): Promise<Fl
|
|
|
360
378
|
defaultTimeout = 100,
|
|
361
379
|
release = "",
|
|
362
380
|
retention = "30d",
|
|
381
|
+
runId = generateRunId(),
|
|
363
382
|
} = options;
|
|
364
383
|
|
|
365
384
|
const retentionDays = parseRetention(retention);
|
|
@@ -379,15 +398,8 @@ export async function RL(secretKey: string, options: RLOptions = {}): Promise<Fl
|
|
|
379
398
|
// Already registered
|
|
380
399
|
}
|
|
381
400
|
|
|
382
|
-
// Check for timed-out flows (fire-and-forget)
|
|
383
|
-
try {
|
|
384
|
-
sdk.conn.reducers.checkTimeouts({ keyHash });
|
|
385
|
-
} catch {
|
|
386
|
-
// Non-critical
|
|
387
|
-
}
|
|
388
|
-
|
|
389
401
|
// Root flow — creation runs in background, logs queue until ready
|
|
390
|
-
const root = new Flow(sdk, keyHash, 0n, "/", 0, release);
|
|
402
|
+
const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
|
|
391
403
|
root._create(); // fire-and-forget — resolves _ready when server assigns ID
|
|
392
404
|
return root;
|
|
393
405
|
}
|
|
@@ -405,7 +417,7 @@ export async function restoreFlow(secretKey: string, exportedId: string, options
|
|
|
405
417
|
const sdk = new SdkConnection(host, dbName);
|
|
406
418
|
await sdk.connect();
|
|
407
419
|
|
|
408
|
-
const flow = new Flow(sdk, keyHash, 0n, "restored", 100);
|
|
420
|
+
const flow = new Flow(sdk, keyHash, 0n, "restored", 100, "", parsed.runId || "");
|
|
409
421
|
(flow as any)._id = BigInt(parsed.flowId);
|
|
410
422
|
(flow as any)._exportToken = parsed.exportToken;
|
|
411
423
|
(flow as any)._resolveReady();
|
|
@@ -423,3 +435,12 @@ export function generateKey(): string {
|
|
|
423
435
|
.join("")
|
|
424
436
|
);
|
|
425
437
|
}
|
|
438
|
+
|
|
439
|
+
/** Generate a random run ID (pass to subprocesses to link flows) */
|
|
440
|
+
export function generateRunId(): string {
|
|
441
|
+
const bytes = new Uint8Array(8);
|
|
442
|
+
crypto.getRandomValues(bytes);
|
|
443
|
+
return Array.from(bytes)
|
|
444
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
445
|
+
.join("");
|
|
446
|
+
}
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
// Import all reducer arg schemas
|
|
37
37
|
import AddLogReducer from "./add_log_reducer";
|
|
38
38
|
import AddLogsBatchReducer from "./add_logs_batch_reducer";
|
|
39
|
-
import CheckTimeoutsReducer from "./check_timeouts_reducer";
|
|
40
39
|
import CreateRootFlowReducer from "./create_root_flow_reducer";
|
|
41
40
|
import CreateSubFlowReducer from "./create_sub_flow_reducer";
|
|
42
41
|
import FinishActionReducer from "./finish_action_reducer";
|
|
@@ -127,7 +126,6 @@ const tablesSchema = __schema({
|
|
|
127
126
|
const reducersSchema = __reducers(
|
|
128
127
|
__reducerSchema("add_log", AddLogReducer),
|
|
129
128
|
__reducerSchema("add_logs_batch", AddLogsBatchReducer),
|
|
130
|
-
__reducerSchema("check_timeouts", CheckTimeoutsReducer),
|
|
131
129
|
__reducerSchema("create_root_flow", CreateRootFlowReducer),
|
|
132
130
|
__reducerSchema("create_sub_flow", CreateSubFlowReducer),
|
|
133
131
|
__reducerSchema("finish_action", FinishActionReducer),
|
|
@@ -8,7 +8,6 @@ import { type Infer as __Infer } from "spacetimedb";
|
|
|
8
8
|
// Import all reducer arg schemas
|
|
9
9
|
import AddLogReducer from "../add_log_reducer";
|
|
10
10
|
import AddLogsBatchReducer from "../add_logs_batch_reducer";
|
|
11
|
-
import CheckTimeoutsReducer from "../check_timeouts_reducer";
|
|
12
11
|
import CreateRootFlowReducer from "../create_root_flow_reducer";
|
|
13
12
|
import CreateSubFlowReducer from "../create_sub_flow_reducer";
|
|
14
13
|
import FinishActionReducer from "../finish_action_reducer";
|
|
@@ -19,7 +18,6 @@ import UpdateErrorGroupStatusReducer from "../update_error_group_status_reducer"
|
|
|
19
18
|
|
|
20
19
|
export type AddLogParams = __Infer<typeof AddLogReducer>;
|
|
21
20
|
export type AddLogsBatchParams = __Infer<typeof AddLogsBatchReducer>;
|
|
22
|
-
export type CheckTimeoutsParams = __Infer<typeof CheckTimeoutsReducer>;
|
|
23
21
|
export type CreateRootFlowParams = __Infer<typeof CreateRootFlowReducer>;
|
|
24
22
|
export type CreateSubFlowParams = __Infer<typeof CreateSubFlowReducer>;
|
|
25
23
|
export type FinishActionParams = __Infer<typeof FinishActionReducer>;
|
|
@@ -46,6 +46,7 @@ export type ErrorGroup = __Infer<typeof ErrorGroup>;
|
|
|
46
46
|
export const Flow = __t.object("Flow", {
|
|
47
47
|
id: __t.u64(),
|
|
48
48
|
keyHash: __t.string(),
|
|
49
|
+
runId: __t.string(),
|
|
49
50
|
parentFlowId: __t.u64(),
|
|
50
51
|
name: __t.string(),
|
|
51
52
|
path: __t.string(),
|
|
@@ -74,3 +75,9 @@ export const LogEntry = __t.object("LogEntry", {
|
|
|
74
75
|
});
|
|
75
76
|
export type LogEntry = __Infer<typeof LogEntry>;
|
|
76
77
|
|
|
78
|
+
export const TimeoutJob = __t.object("TimeoutJob", {
|
|
79
|
+
scheduledId: __t.u64(),
|
|
80
|
+
scheduledAt: __t.scheduleAt(),
|
|
81
|
+
});
|
|
82
|
+
export type TimeoutJob = __Infer<typeof TimeoutJob>;
|
|
83
|
+
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
|
2
|
-
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
|
3
|
-
|
|
4
|
-
/* eslint-disable */
|
|
5
|
-
/* tslint:disable */
|
|
6
|
-
import {
|
|
7
|
-
TypeBuilder as __TypeBuilder,
|
|
8
|
-
t as __t,
|
|
9
|
-
type AlgebraicTypeType as __AlgebraicTypeType,
|
|
10
|
-
type Infer as __Infer,
|
|
11
|
-
} from "spacetimedb";
|
|
12
|
-
|
|
13
|
-
export default {
|
|
14
|
-
keyHash: __t.string(),
|
|
15
|
-
};
|