@radishbot/sdk 0.5.0 → 0.7.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/index.js +111 -117
- package/package.json +1 -1
- package/src/cli.ts +17 -25
- package/src/connection.ts +43 -41
- package/src/index.ts +0 -7
- package/src/module_bindings/index.ts +0 -2
- package/src/module_bindings/types/reducers.ts +0 -2
- package/src/module_bindings/types.ts +6 -0
- package/src/module_bindings/check_timeouts_reducer.ts +0 -15
package/dist/index.js
CHANGED
|
@@ -34,161 +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(),
|
|
51
|
-
|
|
55
|
+
parentFlowId: __t4.u64(),
|
|
56
|
+
name: __t4.string(),
|
|
52
57
|
timeoutSeconds: __t4.u64(),
|
|
53
|
-
exportToken: __t4.string()
|
|
54
|
-
release: __t4.string()
|
|
58
|
+
exportToken: __t4.string()
|
|
55
59
|
};
|
|
56
60
|
|
|
57
|
-
// src/module_bindings/
|
|
61
|
+
// src/module_bindings/finish_action_reducer.ts
|
|
58
62
|
import {
|
|
59
63
|
t as __t5
|
|
60
64
|
} from "spacetimedb";
|
|
61
|
-
var
|
|
65
|
+
var finish_action_reducer_default = {
|
|
62
66
|
keyHash: __t5.string(),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
timeoutSeconds: __t5.u64(),
|
|
66
|
-
exportToken: __t5.string()
|
|
67
|
+
actionId: __t5.u64(),
|
|
68
|
+
status: __t5.string()
|
|
67
69
|
};
|
|
68
70
|
|
|
69
|
-
// src/module_bindings/
|
|
71
|
+
// src/module_bindings/finish_flow_reducer.ts
|
|
70
72
|
import {
|
|
71
73
|
t as __t6
|
|
72
74
|
} from "spacetimedb";
|
|
73
|
-
var
|
|
75
|
+
var finish_flow_reducer_default = {
|
|
74
76
|
keyHash: __t6.string(),
|
|
75
|
-
|
|
76
|
-
status: __t6.string()
|
|
77
|
+
flowId: __t6.u64(),
|
|
78
|
+
status: __t6.string(),
|
|
79
|
+
errorMessage: __t6.string()
|
|
77
80
|
};
|
|
78
81
|
|
|
79
|
-
// src/module_bindings/
|
|
82
|
+
// src/module_bindings/register_key_reducer.ts
|
|
80
83
|
import {
|
|
81
84
|
t as __t7
|
|
82
85
|
} from "spacetimedb";
|
|
83
|
-
var
|
|
86
|
+
var register_key_reducer_default = {
|
|
84
87
|
keyHash: __t7.string(),
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
errorMessage: __t7.string()
|
|
88
|
+
label: __t7.string(),
|
|
89
|
+
retentionDays: __t7.u64()
|
|
88
90
|
};
|
|
89
91
|
|
|
90
|
-
// src/module_bindings/
|
|
92
|
+
// src/module_bindings/start_action_reducer.ts
|
|
91
93
|
import {
|
|
92
94
|
t as __t8
|
|
93
95
|
} from "spacetimedb";
|
|
94
|
-
var
|
|
96
|
+
var start_action_reducer_default = {
|
|
95
97
|
keyHash: __t8.string(),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
flowId: __t8.u64(),
|
|
99
|
+
name: __t8.string()
|
|
98
100
|
};
|
|
99
101
|
|
|
100
|
-
// src/module_bindings/
|
|
102
|
+
// src/module_bindings/update_error_group_status_reducer.ts
|
|
101
103
|
import {
|
|
102
104
|
t as __t9
|
|
103
105
|
} from "spacetimedb";
|
|
104
|
-
var
|
|
106
|
+
var update_error_group_status_reducer_default = {
|
|
105
107
|
keyHash: __t9.string(),
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
errorGroupId: __t9.u64(),
|
|
109
|
+
status: __t9.string()
|
|
108
110
|
};
|
|
109
111
|
|
|
110
|
-
// src/module_bindings/
|
|
112
|
+
// src/module_bindings/action_table.ts
|
|
111
113
|
import {
|
|
112
114
|
t as __t10
|
|
113
115
|
} from "spacetimedb";
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
+
});
|
|
119
124
|
|
|
120
|
-
// src/module_bindings/
|
|
125
|
+
// src/module_bindings/api_key_table.ts
|
|
121
126
|
import {
|
|
122
127
|
t as __t11
|
|
123
128
|
} from "spacetimedb";
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
createdAt: __t11.timestamp().name("created_at"),
|
|
130
|
-
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")
|
|
131
134
|
});
|
|
132
135
|
|
|
133
|
-
// src/module_bindings/
|
|
136
|
+
// src/module_bindings/error_group_table.ts
|
|
134
137
|
import {
|
|
135
138
|
t as __t12
|
|
136
139
|
} from "spacetimedb";
|
|
137
|
-
var
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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")
|
|
142
152
|
});
|
|
143
153
|
|
|
144
|
-
// src/module_bindings/
|
|
154
|
+
// src/module_bindings/flow_table.ts
|
|
145
155
|
import {
|
|
146
156
|
t as __t13
|
|
147
157
|
} from "spacetimedb";
|
|
148
|
-
var
|
|
158
|
+
var flow_table_default = __t13.row({
|
|
149
159
|
id: __t13.u64().primaryKey(),
|
|
150
160
|
keyHash: __t13.string().name("key_hash"),
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
runId: __t13.string().name("run_id"),
|
|
162
|
+
parentFlowId: __t13.u64().name("parent_flow_id"),
|
|
163
|
+
name: __t13.string(),
|
|
153
164
|
path: __t13.string(),
|
|
154
|
-
release: __t13.string(),
|
|
155
|
-
count: __t13.u64(),
|
|
156
165
|
status: __t13.string(),
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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")
|
|
160
171
|
});
|
|
161
172
|
|
|
162
|
-
// src/module_bindings/
|
|
173
|
+
// src/module_bindings/log_entry_table.ts
|
|
163
174
|
import {
|
|
164
175
|
t as __t14
|
|
165
176
|
} from "spacetimedb";
|
|
166
|
-
var
|
|
177
|
+
var log_entry_table_default = __t14.row({
|
|
167
178
|
id: __t14.u64().primaryKey(),
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
status: __t14.string(),
|
|
174
|
-
release: __t14.string(),
|
|
175
|
-
timeoutSeconds: __t14.u64().name("timeout_seconds"),
|
|
176
|
-
createdAt: __t14.timestamp().name("created_at"),
|
|
177
|
-
finishedAt: __t14.u64().name("finished_at"),
|
|
178
|
-
exportToken: __t14.string().name("export_token")
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// src/module_bindings/log_entry_table.ts
|
|
182
|
-
import {
|
|
183
|
-
t as __t15
|
|
184
|
-
} from "spacetimedb";
|
|
185
|
-
var log_entry_table_default = __t15.row({
|
|
186
|
-
id: __t15.u64().primaryKey(),
|
|
187
|
-
flowId: __t15.u64().name("flow_id"),
|
|
188
|
-
level: __t15.string(),
|
|
189
|
-
message: __t15.string(),
|
|
190
|
-
data: __t15.string(),
|
|
191
|
-
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")
|
|
192
184
|
});
|
|
193
185
|
|
|
194
186
|
// src/module_bindings/index.ts
|
|
@@ -257,7 +249,7 @@ var tablesSchema = __schema({
|
|
|
257
249
|
]
|
|
258
250
|
}, log_entry_table_default)
|
|
259
251
|
});
|
|
260
|
-
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));
|
|
261
253
|
var proceduresSchema = __procedures();
|
|
262
254
|
var REMOTE_MODULE = {
|
|
263
255
|
versionInfo: {
|
|
@@ -291,7 +283,6 @@ class SdkConnection {
|
|
|
291
283
|
_dbName;
|
|
292
284
|
_conn = null;
|
|
293
285
|
_connectPromise = null;
|
|
294
|
-
_timeoutInterval = null;
|
|
295
286
|
_keyHash = null;
|
|
296
287
|
_flowWaiters = new Map;
|
|
297
288
|
constructor(host, dbName) {
|
|
@@ -307,16 +298,16 @@ class SdkConnection {
|
|
|
307
298
|
if (this._connectPromise)
|
|
308
299
|
return this._connectPromise;
|
|
309
300
|
this._connectPromise = new Promise((resolve, reject) => {
|
|
310
|
-
|
|
301
|
+
DbConnection.builder().withUri(this._host).withDatabaseName(this._dbName).onConnect((c, _identity, _token) => {
|
|
311
302
|
this._conn = c;
|
|
312
|
-
c.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
c.reducers.checkTimeouts({ keyHash: this._keyHash });
|
|
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);
|
|
318
308
|
}
|
|
319
|
-
}
|
|
309
|
+
});
|
|
310
|
+
c.subscriptionBuilder().onApplied(() => resolve(c)).subscribeToAll();
|
|
320
311
|
}).onConnectError((_ctx, err) => {
|
|
321
312
|
reject(new Error(`SpacetimeDB connection failed: ${err}`));
|
|
322
313
|
}).build();
|
|
@@ -334,36 +325,42 @@ class SdkConnection {
|
|
|
334
325
|
if (f.exportToken === exportToken)
|
|
335
326
|
return f.id;
|
|
336
327
|
}
|
|
337
|
-
return new Promise((resolve) => {
|
|
338
|
-
|
|
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
|
+
});
|
|
339
337
|
reducerCall();
|
|
340
|
-
const
|
|
338
|
+
const interval = setInterval(() => {
|
|
339
|
+
if (resolved) {
|
|
340
|
+
clearInterval(interval);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
341
343
|
for (const f of conn.db.flow.iter()) {
|
|
342
344
|
if (f.exportToken === exportToken) {
|
|
345
|
+
resolved = true;
|
|
346
|
+
clearInterval(interval);
|
|
343
347
|
this._flowWaiters.delete(exportToken);
|
|
344
348
|
resolve(f.id);
|
|
345
|
-
return
|
|
349
|
+
return;
|
|
346
350
|
}
|
|
347
351
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (check() || attempts++ > 100) {
|
|
352
|
+
}, 100);
|
|
353
|
+
setTimeout(() => {
|
|
354
|
+
if (!resolved) {
|
|
355
|
+
resolved = true;
|
|
353
356
|
clearInterval(interval);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
throw new Error(`Flow creation timed out for token ${exportToken}`);
|
|
357
|
-
}
|
|
357
|
+
this._flowWaiters.delete(exportToken);
|
|
358
|
+
reject(new Error(`Flow creation timed out for token ${exportToken}`));
|
|
358
359
|
}
|
|
359
|
-
},
|
|
360
|
+
}, 15000);
|
|
360
361
|
});
|
|
361
362
|
}
|
|
362
363
|
disconnect() {
|
|
363
|
-
if (this._timeoutInterval) {
|
|
364
|
-
clearInterval(this._timeoutInterval);
|
|
365
|
-
this._timeoutInterval = null;
|
|
366
|
-
}
|
|
367
364
|
if (this._conn) {
|
|
368
365
|
this._conn.disconnect();
|
|
369
366
|
this._conn = null;
|
|
@@ -668,9 +665,6 @@ async function RL(secretKey, options = {}) {
|
|
|
668
665
|
try {
|
|
669
666
|
sdk.conn.reducers.registerKey({ keyHash, label, retentionDays: BigInt(retentionDays) });
|
|
670
667
|
} catch {}
|
|
671
|
-
try {
|
|
672
|
-
sdk.conn.reducers.checkTimeouts({ keyHash });
|
|
673
|
-
} catch {}
|
|
674
668
|
const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
|
|
675
669
|
root._create();
|
|
676
670
|
return root;
|
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();
|
|
@@ -360,12 +352,15 @@ async function cmdTail(keyHash: string) {
|
|
|
360
352
|
.onApplied(() => {
|
|
361
353
|
// Seed known flows and seen logs
|
|
362
354
|
for (const f of c.db.flow.iter()) {
|
|
363
|
-
|
|
355
|
+
flowNames.set(f.id, f.name === "/" ? "root" : f.name);
|
|
364
356
|
}
|
|
365
357
|
for (const l of c.db.logEntry.iter()) seen.add(l.id);
|
|
366
358
|
resolve(c);
|
|
367
359
|
})
|
|
368
|
-
.
|
|
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
|
+
]);
|
|
369
364
|
})
|
|
370
365
|
.onConnectError((_ctx, err) => reject(new Error(`Connection failed: ${err}`)))
|
|
371
366
|
.build();
|
|
@@ -373,9 +368,9 @@ async function cmdTail(keyHash: string) {
|
|
|
373
368
|
|
|
374
369
|
// Poll for new logs
|
|
375
370
|
setInterval(() => {
|
|
376
|
-
// Update flow names
|
|
371
|
+
// Update flow names (subscription already filters by key)
|
|
377
372
|
for (const f of conn.db.flow.iter()) {
|
|
378
|
-
if (
|
|
373
|
+
if (!flowNames.has(f.id)) {
|
|
379
374
|
flowNames.set(f.id, f.name === "/" ? "root" : f.name);
|
|
380
375
|
}
|
|
381
376
|
}
|
|
@@ -383,11 +378,8 @@ async function cmdTail(keyHash: string) {
|
|
|
383
378
|
const newLogs: any[] = [];
|
|
384
379
|
for (const l of conn.db.logEntry.iter()) {
|
|
385
380
|
if (!seen.has(l.id) && l.level !== "flow" && l.level !== "action") {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
seen.add(l.id);
|
|
389
|
-
newLogs.push(l);
|
|
390
|
-
}
|
|
381
|
+
seen.add(l.id);
|
|
382
|
+
newLogs.push(l);
|
|
391
383
|
}
|
|
392
384
|
}
|
|
393
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
|
|
@@ -29,25 +28,24 @@ export class SdkConnection {
|
|
|
29
28
|
if (this._connectPromise) return this._connectPromise;
|
|
30
29
|
|
|
31
30
|
this._connectPromise = new Promise<StdbConnection>((resolve, reject) => {
|
|
32
|
-
|
|
31
|
+
StdbConnection.builder()
|
|
33
32
|
.withUri(this._host)
|
|
34
33
|
.withDatabaseName(this._dbName)
|
|
35
34
|
.onConnect((c, _identity, _token) => {
|
|
36
35
|
this._conn = c;
|
|
37
36
|
|
|
38
|
-
//
|
|
39
|
-
c.
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Periodic timeout check (every 30s)
|
|
46
|
-
this._timeoutInterval = setInterval(() => {
|
|
47
|
-
if (this._keyHash) {
|
|
48
|
-
c.reducers.checkTimeouts({ keyHash: this._keyHash });
|
|
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);
|
|
49
43
|
}
|
|
50
|
-
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
c.subscriptionBuilder()
|
|
47
|
+
.onApplied(() => resolve(c))
|
|
48
|
+
.subscribeToAll();
|
|
51
49
|
})
|
|
52
50
|
.onConnectError((_ctx, err) => {
|
|
53
51
|
reject(new Error(`SpacetimeDB connection failed: ${err}`));
|
|
@@ -59,7 +57,7 @@ export class SdkConnection {
|
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
get conn(): StdbConnection {
|
|
62
|
-
if (!this._conn) throw new Error(
|
|
60
|
+
if (!this._conn) throw new Error("Not connected");
|
|
63
61
|
return this._conn;
|
|
64
62
|
}
|
|
65
63
|
|
|
@@ -67,10 +65,7 @@ export class SdkConnection {
|
|
|
67
65
|
* Call a reducer and wait for the flow to appear in the subscription.
|
|
68
66
|
* Returns the server-assigned flow ID.
|
|
69
67
|
*/
|
|
70
|
-
async createFlowAndResolveId(
|
|
71
|
-
reducerCall: () => void,
|
|
72
|
-
exportToken: string
|
|
73
|
-
): Promise<bigint> {
|
|
68
|
+
async createFlowAndResolveId(reducerCall: () => void, exportToken: string): Promise<bigint> {
|
|
74
69
|
const conn = this.conn;
|
|
75
70
|
|
|
76
71
|
// Check if flow already exists (from a previous subscription update)
|
|
@@ -78,44 +73,51 @@ export class SdkConnection {
|
|
|
78
73
|
if (f.exportToken === exportToken) return f.id;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
|
-
return new Promise<bigint>((resolve) => {
|
|
82
|
-
|
|
83
|
-
|
|
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
|
+
});
|
|
84
87
|
|
|
85
88
|
// Call the reducer
|
|
86
89
|
reducerCall();
|
|
87
90
|
|
|
88
|
-
//
|
|
89
|
-
const
|
|
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
|
+
}
|
|
90
97
|
for (const f of conn.db.flow.iter()) {
|
|
91
98
|
if (f.exportToken === exportToken) {
|
|
99
|
+
resolved = true;
|
|
100
|
+
clearInterval(interval);
|
|
92
101
|
this._flowWaiters.delete(exportToken);
|
|
93
102
|
resolve(f.id);
|
|
94
|
-
return
|
|
103
|
+
return;
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
|
-
|
|
98
|
-
};
|
|
106
|
+
}, 100);
|
|
99
107
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
// Timeout after 15 seconds (properly rejects the promise)
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
if (!resolved) {
|
|
111
|
+
resolved = true;
|
|
104
112
|
clearInterval(interval);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
throw new Error(`Flow creation timed out for token ${exportToken}`);
|
|
108
|
-
}
|
|
113
|
+
this._flowWaiters.delete(exportToken);
|
|
114
|
+
reject(new Error(`Flow creation timed out for token ${exportToken}`));
|
|
109
115
|
}
|
|
110
|
-
},
|
|
116
|
+
}, 15_000);
|
|
111
117
|
});
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
disconnect(): void {
|
|
115
|
-
if (this._timeoutInterval) {
|
|
116
|
-
clearInterval(this._timeoutInterval);
|
|
117
|
-
this._timeoutInterval = null;
|
|
118
|
-
}
|
|
119
121
|
if (this._conn) {
|
|
120
122
|
this._conn.disconnect();
|
|
121
123
|
this._conn = null;
|
package/src/index.ts
CHANGED
|
@@ -398,13 +398,6 @@ export async function RL(secretKey: string, options: RLOptions = {}): Promise<Fl
|
|
|
398
398
|
// Already registered
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
// Check for timed-out flows (fire-and-forget)
|
|
402
|
-
try {
|
|
403
|
-
sdk.conn.reducers.checkTimeouts({ keyHash });
|
|
404
|
-
} catch {
|
|
405
|
-
// Non-critical
|
|
406
|
-
}
|
|
407
|
-
|
|
408
401
|
// Root flow — creation runs in background, logs queue until ready
|
|
409
402
|
const root = new Flow(sdk, keyHash, 0n, "/", 0, release, runId);
|
|
410
403
|
root._create(); // fire-and-forget — resolves _ready when server assigns ID
|
|
@@ -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>;
|
|
@@ -75,3 +75,9 @@ export const LogEntry = __t.object("LogEntry", {
|
|
|
75
75
|
});
|
|
76
76
|
export type LogEntry = __Infer<typeof LogEntry>;
|
|
77
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
|
-
};
|