spacetimedb 2.0.4 → 2.2.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/LICENSE.txt +2 -2
- package/dist/angular/index.cjs +9 -3
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.mjs +9 -3
- package/dist/angular/index.mjs.map +1 -1
- package/dist/browser/angular/index.mjs +9 -3
- package/dist/browser/angular/index.mjs.map +1 -1
- package/dist/browser/react/index.mjs +62 -7
- package/dist/browser/react/index.mjs.map +1 -1
- package/dist/browser/svelte/index.mjs +9 -3
- package/dist/browser/svelte/index.mjs.map +1 -1
- package/dist/browser/vue/index.mjs +9 -3
- package/dist/browser/vue/index.mjs.map +1 -1
- package/dist/index.browser.mjs +481 -146
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +481 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +481 -146
- package/dist/index.mjs.map +1 -1
- package/dist/lib/algebraic_type.d.ts.map +1 -1
- package/dist/lib/binary_reader.d.ts +1 -1
- package/dist/lib/binary_reader.d.ts.map +1 -1
- package/dist/lib/binary_writer.d.ts +2 -1
- package/dist/lib/binary_writer.d.ts.map +1 -1
- package/dist/lib/filter.d.ts +2 -1
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/query.d.ts +10 -5
- package/dist/lib/query.d.ts.map +1 -1
- package/dist/lib/table.d.ts +12 -1
- package/dist/lib/table.d.ts.map +1 -1
- package/dist/min/index.browser.mjs +1 -1
- package/dist/min/index.browser.mjs.map +1 -1
- package/dist/min/react/index.mjs +1 -1
- package/dist/min/react/index.mjs.map +1 -1
- package/dist/min/sdk/index.browser.mjs +1 -1
- package/dist/min/sdk/index.browser.mjs.map +1 -1
- package/dist/react/index.cjs +62 -6
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.mjs +62 -7
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useProcedure.d.ts +4 -0
- package/dist/react/useProcedure.d.ts.map +1 -0
- package/dist/react/useTable.d.ts +2 -0
- package/dist/react/useTable.d.ts.map +1 -1
- package/dist/sdk/db_connection_builder.d.ts +3 -3
- package/dist/sdk/db_connection_builder.d.ts.map +1 -1
- package/dist/sdk/db_connection_impl.d.ts +3 -3
- package/dist/sdk/db_connection_impl.d.ts.map +1 -1
- package/dist/sdk/decompress.d.ts +1 -1
- package/dist/sdk/decompress.d.ts.map +1 -1
- package/dist/sdk/index.browser.mjs +477 -144
- package/dist/sdk/index.browser.mjs.map +1 -1
- package/dist/sdk/index.cjs +477 -144
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.mjs +477 -144
- package/dist/sdk/index.mjs.map +1 -1
- package/dist/sdk/table_cache.d.ts +1 -0
- package/dist/sdk/table_cache.d.ts.map +1 -1
- package/dist/sdk/type_utils.d.ts +4 -1
- package/dist/sdk/type_utils.d.ts.map +1 -1
- package/dist/sdk/websocket_decompress_adapter.d.ts +5 -21
- package/dist/sdk/websocket_decompress_adapter.d.ts.map +1 -1
- package/dist/sdk/websocket_protocols.d.ts +6 -0
- package/dist/sdk/websocket_protocols.d.ts.map +1 -0
- package/dist/sdk/websocket_test_adapter.d.ts +14 -18
- package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
- package/dist/sdk/websocket_v3_frames.d.ts +9 -0
- package/dist/sdk/websocket_v3_frames.d.ts.map +1 -0
- package/dist/sdk/ws.d.ts +26 -1
- package/dist/sdk/ws.d.ts.map +1 -1
- package/dist/server/http_internal.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.mjs +76 -15
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/runtime.d.ts +29 -2
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/svelte/index.cjs +9 -3
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.mjs +9 -3
- package/dist/svelte/index.mjs.map +1 -1
- package/dist/tanstack/index.cjs +9 -3
- package/dist/tanstack/index.cjs.map +1 -1
- package/dist/tanstack/index.mjs +9 -3
- package/dist/tanstack/index.mjs.map +1 -1
- package/dist/vue/index.cjs +9 -3
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.mjs +9 -3
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/lib/algebraic_type.ts +5 -1
- package/src/lib/binary_reader.ts +5 -2
- package/src/lib/binary_writer.ts +7 -1
- package/src/lib/filter.ts +12 -1
- package/src/lib/query.ts +60 -19
- package/src/lib/table.ts +15 -2
- package/src/react/index.ts +1 -0
- package/src/react/useProcedure.ts +60 -0
- package/src/react/useTable.ts +22 -2
- package/src/sdk/db_connection_builder.ts +16 -7
- package/src/sdk/db_connection_impl.ts +404 -89
- package/src/sdk/decompress.ts +7 -23
- package/src/sdk/table_cache.ts +5 -5
- package/src/sdk/type_utils.ts +10 -1
- package/src/sdk/websocket_decompress_adapter.ts +15 -77
- package/src/sdk/websocket_protocols.ts +25 -0
- package/src/sdk/websocket_test_adapter.ts +65 -29
- package/src/sdk/websocket_v3_frames.ts +126 -0
- package/src/sdk/ws.ts +81 -3
- package/src/server/http_internal.ts +10 -1
- package/src/server/index.ts +2 -1
- package/src/server/runtime.ts +39 -1
- package/src/server/sys.d.ts +4 -0
- package/src/server/view.test-d.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spacetimedb",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "API and ABI bindings for the SpacetimeDB TypeScript module library",
|
|
5
5
|
"homepage": "https://github.com/clockworklabs/SpacetimeDB#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"name": "esm (gzip)",
|
|
95
95
|
"path": "dist/index.mjs",
|
|
96
96
|
"gzip": true,
|
|
97
|
-
"limit": "
|
|
97
|
+
"limit": "48 kB"
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "esm (uncompressed)",
|
|
@@ -535,7 +535,11 @@ const view = reader.view;
|
|
|
535
535
|
${ty.elements
|
|
536
536
|
.map(({ name, algebraicType: { tag } }) =>
|
|
537
537
|
tag in primitiveJSName
|
|
538
|
-
?
|
|
538
|
+
? tag === 'Bool'
|
|
539
|
+
? `\
|
|
540
|
+
result.${name} = view.getUint8(reader.offset) !== 0;
|
|
541
|
+
reader.offset += 1;`
|
|
542
|
+
: `\
|
|
539
543
|
result.${name} = view.get${primitiveJSName[tag as JSPrimitives]}(reader.offset, ${primitiveSizes[tag] > 1 ? 'true' : ''});
|
|
540
544
|
reader.offset += ${primitiveSizes[tag]};`
|
|
541
545
|
: `result.${name} = reader.read${tag}();`
|
package/src/lib/binary_reader.ts
CHANGED
|
@@ -25,8 +25,11 @@ export default class BinaryReader {
|
|
|
25
25
|
this.offset = 0;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
reset(
|
|
29
|
-
this.view =
|
|
28
|
+
reset(input: Uint8Array | DataView) {
|
|
29
|
+
this.view =
|
|
30
|
+
input instanceof DataView
|
|
31
|
+
? input
|
|
32
|
+
: new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
30
33
|
this.offset = 0;
|
|
31
34
|
}
|
|
32
35
|
|
package/src/lib/binary_writer.ts
CHANGED
|
@@ -63,7 +63,7 @@ export default class BinaryWriter {
|
|
|
63
63
|
return fromByteArray(this.getBuffer());
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
getBuffer(): Uint8Array {
|
|
66
|
+
getBuffer(): Uint8Array<ArrayBuffer> {
|
|
67
67
|
return new Uint8Array(this.buffer.buffer, 0, this.offset);
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -93,6 +93,12 @@ export default class BinaryWriter {
|
|
|
93
93
|
this.offset += 1;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
writeBytes(value: Uint8Array): void {
|
|
97
|
+
this.expandBuffer(value.length);
|
|
98
|
+
new Uint8Array(this.buffer.buffer, this.offset, value.length).set(value);
|
|
99
|
+
this.offset += value.length;
|
|
100
|
+
}
|
|
101
|
+
|
|
96
102
|
writeI8(value: number): void {
|
|
97
103
|
this.expandBuffer(1);
|
|
98
104
|
this.view.setInt8(this.offset, value);
|
package/src/lib/filter.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { RowType, UntypedTableDef } from './table';
|
|
2
|
+
import { Timestamp } from './timestamp';
|
|
2
3
|
import { Uuid } from './uuid';
|
|
3
4
|
|
|
4
|
-
export type Value = string | number | boolean | Uuid;
|
|
5
|
+
export type Value = string | number | boolean | Uuid | Timestamp;
|
|
5
6
|
|
|
6
7
|
export type Expr<Column extends string> =
|
|
7
8
|
| { type: 'eq'; key: Column; value: Value }
|
|
@@ -77,6 +78,13 @@ export function evaluate<Column extends string>(
|
|
|
77
78
|
if (v instanceof Uuid && typeof expr.value === 'string') {
|
|
78
79
|
return v.toString() === expr.value;
|
|
79
80
|
}
|
|
81
|
+
|
|
82
|
+
if (v instanceof Timestamp) {
|
|
83
|
+
// Value of the Column and passed Value are both Timestamps so compare microseconds.
|
|
84
|
+
if (expr.value instanceof Timestamp) {
|
|
85
|
+
return v.microsSinceUnixEpoch === expr.value.microsSinceUnixEpoch;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
89
|
return false;
|
|
82
90
|
}
|
|
@@ -103,6 +111,9 @@ function formatValue(v: Value): string {
|
|
|
103
111
|
if (v instanceof Uuid) {
|
|
104
112
|
return `'${v.toString()}'`;
|
|
105
113
|
}
|
|
114
|
+
if (v instanceof Timestamp) {
|
|
115
|
+
return `'${v.toISOString()}'`;
|
|
116
|
+
}
|
|
106
117
|
|
|
107
118
|
return '';
|
|
108
119
|
}
|
package/src/lib/query.ts
CHANGED
|
@@ -348,7 +348,8 @@ function createRowExpr<TableDef extends TypedTableDef>(
|
|
|
348
348
|
columnBuilder.typeBuilder.algebraicType as InferSpacetimeTypeOfColumn<
|
|
349
349
|
TableDef,
|
|
350
350
|
typeof columnName
|
|
351
|
-
|
|
351
|
+
>,
|
|
352
|
+
columnBuilder.columnMetadata.name
|
|
352
353
|
);
|
|
353
354
|
row[columnName] = Object.freeze(column);
|
|
354
355
|
}
|
|
@@ -438,7 +439,10 @@ export class ColumnExpression<
|
|
|
438
439
|
ColumnName extends ColumnNames<TableDef>,
|
|
439
440
|
> {
|
|
440
441
|
readonly type = 'column' as const;
|
|
442
|
+
// This is the column accessor
|
|
441
443
|
readonly column: ColumnName;
|
|
444
|
+
// The name of the column in the database.
|
|
445
|
+
readonly columnName: string;
|
|
442
446
|
readonly table: TableDef['sourceName'];
|
|
443
447
|
// phantom: actual runtime value is undefined
|
|
444
448
|
readonly tsValueType?: RowType<TableDef>[ColumnName];
|
|
@@ -447,10 +451,12 @@ export class ColumnExpression<
|
|
|
447
451
|
constructor(
|
|
448
452
|
table: TableDef['sourceName'],
|
|
449
453
|
column: ColumnName,
|
|
450
|
-
spacetimeType: InferSpacetimeTypeOfColumn<TableDef, ColumnName
|
|
454
|
+
spacetimeType: InferSpacetimeTypeOfColumn<TableDef, ColumnName>,
|
|
455
|
+
columnName?: string
|
|
451
456
|
) {
|
|
452
457
|
this.table = table;
|
|
453
458
|
this.column = column;
|
|
459
|
+
this.columnName = columnName || column;
|
|
454
460
|
this.spacetimeType = spacetimeType;
|
|
455
461
|
}
|
|
456
462
|
|
|
@@ -710,15 +716,38 @@ type BooleanExprData<Table extends TypedTableDef> = (
|
|
|
710
716
|
_tableType?: Table;
|
|
711
717
|
};
|
|
712
718
|
|
|
719
|
+
type AndOrMixedTableScopeError = {
|
|
720
|
+
readonly 'Cannot combine predicates from different table scopes with and/or. In semijoin on(...), keep only the join equality and move extra predicates to .where(...).': never;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
type RequireSameAndOrTable<
|
|
724
|
+
Expected extends TypedTableDef,
|
|
725
|
+
Actual extends TypedTableDef,
|
|
726
|
+
> = [Expected] extends [Actual]
|
|
727
|
+
? [Actual] extends [Expected]
|
|
728
|
+
? unknown
|
|
729
|
+
: AndOrMixedTableScopeError
|
|
730
|
+
: AndOrMixedTableScopeError;
|
|
731
|
+
|
|
713
732
|
export class BooleanExpr<Table extends TypedTableDef> {
|
|
714
733
|
constructor(readonly data: BooleanExprData<Table>) {}
|
|
715
734
|
|
|
716
|
-
and
|
|
717
|
-
|
|
735
|
+
and<OtherTable extends TypedTableDef>(
|
|
736
|
+
other: BooleanExpr<OtherTable> & RequireSameAndOrTable<Table, OtherTable>
|
|
737
|
+
): BooleanExpr<Table> {
|
|
738
|
+
return new BooleanExpr({
|
|
739
|
+
type: 'and',
|
|
740
|
+
clauses: [this.data, other.data as BooleanExprData<Table>],
|
|
741
|
+
});
|
|
718
742
|
}
|
|
719
743
|
|
|
720
|
-
or
|
|
721
|
-
|
|
744
|
+
or<OtherTable extends TypedTableDef>(
|
|
745
|
+
other: BooleanExpr<OtherTable> & RequireSameAndOrTable<Table, OtherTable>
|
|
746
|
+
): BooleanExpr<Table> {
|
|
747
|
+
return new BooleanExpr({
|
|
748
|
+
type: 'or',
|
|
749
|
+
clauses: [this.data, other.data as BooleanExprData<Table>],
|
|
750
|
+
});
|
|
722
751
|
}
|
|
723
752
|
|
|
724
753
|
not(): BooleanExpr<Table> {
|
|
@@ -732,28 +761,40 @@ export function not<T extends TypedTableDef>(
|
|
|
732
761
|
return new BooleanExpr({ type: 'not', clause: clause.data });
|
|
733
762
|
}
|
|
734
763
|
|
|
735
|
-
export function and<
|
|
736
|
-
|
|
737
|
-
|
|
764
|
+
export function and<
|
|
765
|
+
Table extends TypedTableDef,
|
|
766
|
+
OtherTable extends TypedTableDef,
|
|
767
|
+
>(
|
|
768
|
+
first: BooleanExpr<Table>,
|
|
769
|
+
second: BooleanExpr<OtherTable> & RequireSameAndOrTable<Table, OtherTable>,
|
|
770
|
+
...rest: readonly BooleanExpr<Table>[]
|
|
771
|
+
): BooleanExpr<Table> {
|
|
772
|
+
const clauses = [first, second, ...rest];
|
|
738
773
|
return new BooleanExpr({
|
|
739
774
|
type: 'and',
|
|
740
775
|
clauses: clauses.map(c => c.data) as [
|
|
741
|
-
BooleanExprData<
|
|
742
|
-
BooleanExprData<
|
|
743
|
-
...BooleanExprData<
|
|
776
|
+
BooleanExprData<Table>,
|
|
777
|
+
BooleanExprData<Table>,
|
|
778
|
+
...BooleanExprData<Table>[],
|
|
744
779
|
],
|
|
745
780
|
});
|
|
746
781
|
}
|
|
747
782
|
|
|
748
|
-
export function or<
|
|
749
|
-
|
|
750
|
-
|
|
783
|
+
export function or<
|
|
784
|
+
Table extends TypedTableDef,
|
|
785
|
+
OtherTable extends TypedTableDef,
|
|
786
|
+
>(
|
|
787
|
+
first: BooleanExpr<Table>,
|
|
788
|
+
second: BooleanExpr<OtherTable> & RequireSameAndOrTable<Table, OtherTable>,
|
|
789
|
+
...rest: readonly BooleanExpr<Table>[]
|
|
790
|
+
): BooleanExpr<Table> {
|
|
791
|
+
const clauses = [first, second, ...rest];
|
|
751
792
|
return new BooleanExpr({
|
|
752
793
|
type: 'or',
|
|
753
794
|
clauses: clauses.map(c => c.data) as [
|
|
754
|
-
BooleanExprData<
|
|
755
|
-
BooleanExprData<
|
|
756
|
-
...BooleanExprData<
|
|
795
|
+
BooleanExprData<Table>,
|
|
796
|
+
BooleanExprData<Table>,
|
|
797
|
+
...BooleanExprData<Table>[],
|
|
757
798
|
],
|
|
758
799
|
});
|
|
759
800
|
}
|
|
@@ -803,7 +844,7 @@ function valueExprToSql<Table extends TypedTableDef>(
|
|
|
803
844
|
return literalValueToSql(expr.value);
|
|
804
845
|
}
|
|
805
846
|
const table = tableAlias ?? expr.table;
|
|
806
|
-
return `${quoteIdentifier(table)}.${quoteIdentifier(expr.
|
|
847
|
+
return `${quoteIdentifier(table)}.${quoteIdentifier(expr.columnName)}`;
|
|
807
848
|
}
|
|
808
849
|
|
|
809
850
|
function literalValueToSql(value: unknown): string {
|
package/src/lib/table.ts
CHANGED
|
@@ -239,7 +239,12 @@ export type ReadonlyTable<TableDef extends UntypedTableDef> = Prettify<
|
|
|
239
239
|
>;
|
|
240
240
|
|
|
241
241
|
export interface ReadonlyTableMethods<TableDef extends UntypedTableDef> {
|
|
242
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* Returns the number of rows in this table.
|
|
244
|
+
*
|
|
245
|
+
* This reads datastore metadata, so it runs in constant time.
|
|
246
|
+
* It also takes into account modifications by the current transaction.
|
|
247
|
+
*/
|
|
243
248
|
count(): bigint;
|
|
244
249
|
|
|
245
250
|
/** Iterate over all rows in the TX state. Rust Iterator<Item=Row> → TS IterableIterator<Row>. */
|
|
@@ -263,6 +268,13 @@ export interface TableMethods<TableDef extends UntypedTableDef>
|
|
|
263
268
|
|
|
264
269
|
/** Delete a row equal to `row`. Returns true if something was deleted. */
|
|
265
270
|
delete(row: Prettify<RowType<TableDef>>): boolean;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Clears the table of all rows.
|
|
274
|
+
* Returns the number of rows deleted,
|
|
275
|
+
* i.e., the return value of `this.count()` before this call.
|
|
276
|
+
*/
|
|
277
|
+
clear(): bigint;
|
|
266
278
|
}
|
|
267
279
|
|
|
268
280
|
/**
|
|
@@ -399,7 +411,8 @@ export function table<Row extends RowObj, const Opts extends TableOpts<Row>>(
|
|
|
399
411
|
});
|
|
400
412
|
}
|
|
401
413
|
|
|
402
|
-
|
|
414
|
+
// Check for defaultValue on the property to allow for 0, false, '', and undefined as defaults
|
|
415
|
+
if (Object.prototype.hasOwnProperty.call(meta, 'defaultValue')) {
|
|
403
416
|
const writer = new BinaryWriter(16);
|
|
404
417
|
builder.serialize(writer, meta.defaultValue);
|
|
405
418
|
defaultValues.push({
|
package/src/react/index.ts
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import type { UntypedProcedureDef } from '../sdk/procedures';
|
|
3
|
+
import { useSpacetimeDB } from './useSpacetimeDB';
|
|
4
|
+
import type {
|
|
5
|
+
ProcedureParamsType,
|
|
6
|
+
ProcedureReturnType,
|
|
7
|
+
} from '../sdk/type_utils';
|
|
8
|
+
|
|
9
|
+
export function useProcedure<ProcedureDef extends UntypedProcedureDef>(
|
|
10
|
+
procedureDef: ProcedureDef
|
|
11
|
+
): (
|
|
12
|
+
...params: ProcedureParamsType<ProcedureDef>
|
|
13
|
+
) => Promise<ProcedureReturnType<ProcedureDef>> {
|
|
14
|
+
const { getConnection, isActive } = useSpacetimeDB();
|
|
15
|
+
const procedureName = procedureDef.accessorName;
|
|
16
|
+
|
|
17
|
+
// Holds calls made before the connection exists
|
|
18
|
+
const queueRef = useRef<
|
|
19
|
+
{
|
|
20
|
+
params: ProcedureParamsType<ProcedureDef>;
|
|
21
|
+
resolve: (val: any) => void;
|
|
22
|
+
reject: (err: unknown) => void;
|
|
23
|
+
}[]
|
|
24
|
+
>([]);
|
|
25
|
+
|
|
26
|
+
// Flush when we finally have a connection
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const conn = getConnection();
|
|
29
|
+
if (!conn) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const fn = (conn.procedures as any)[procedureName] as (
|
|
33
|
+
...p: ProcedureParamsType<ProcedureDef>
|
|
34
|
+
) => Promise<ProcedureReturnType<ProcedureDef>>;
|
|
35
|
+
if (queueRef.current.length) {
|
|
36
|
+
const pending = queueRef.current.splice(0);
|
|
37
|
+
for (const item of pending) {
|
|
38
|
+
fn(...item.params).then(item.resolve, item.reject);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, [getConnection, procedureName, isActive]);
|
|
42
|
+
|
|
43
|
+
return useCallback(
|
|
44
|
+
(...params: ProcedureParamsType<ProcedureDef>) => {
|
|
45
|
+
const conn = getConnection();
|
|
46
|
+
if (!conn) {
|
|
47
|
+
return new Promise<ProcedureReturnType<ProcedureDef>>(
|
|
48
|
+
(resolve, reject) => {
|
|
49
|
+
queueRef.current.push({ params, resolve, reject });
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const fn = (conn.procedures as any)[procedureName] as (
|
|
54
|
+
...p: ProcedureParamsType<ProcedureDef>
|
|
55
|
+
) => Promise<ProcedureReturnType<ProcedureDef>>;
|
|
56
|
+
return fn(...params);
|
|
57
|
+
},
|
|
58
|
+
[getConnection, procedureName]
|
|
59
|
+
);
|
|
60
|
+
}
|
package/src/react/useTable.ts
CHANGED
|
@@ -24,6 +24,8 @@ export interface UseTableCallbacks<RowType> {
|
|
|
24
24
|
onInsert?: (row: RowType) => void;
|
|
25
25
|
onDelete?: (row: RowType) => void;
|
|
26
26
|
onUpdate?: (oldRow: RowType, newRow: RowType) => void;
|
|
27
|
+
/** Whether the subscription is active. Defaults to `true`. */
|
|
28
|
+
enabled?: boolean;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
type MembershipChange = 'enter' | 'leave' | 'stayIn' | 'stayOut';
|
|
@@ -67,6 +69,7 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
67
69
|
callbacks?: UseTableCallbacks<Prettify<RowType<TableDef>>>
|
|
68
70
|
): [readonly Prettify<RowType<TableDef>>[], boolean] {
|
|
69
71
|
type UseTableRowType = RowType<TableDef>;
|
|
72
|
+
const enabled = callbacks?.enabled ?? true;
|
|
70
73
|
const accessorName = getQueryAccessorName(query);
|
|
71
74
|
const whereExpr = getQueryWhereClause(query);
|
|
72
75
|
|
|
@@ -93,6 +96,9 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
93
96
|
readonly Prettify<UseTableRowType>[],
|
|
94
97
|
boolean,
|
|
95
98
|
] => {
|
|
99
|
+
if (!enabled) {
|
|
100
|
+
return [[], true];
|
|
101
|
+
}
|
|
96
102
|
const connection = connectionState.getConnection();
|
|
97
103
|
if (!connection) {
|
|
98
104
|
return [[], false];
|
|
@@ -104,8 +110,10 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
104
110
|
) as Prettify<UseTableRowType>[])
|
|
105
111
|
: (Array.from(table.iter()) as Prettify<UseTableRowType>[]);
|
|
106
112
|
return [result, subscribeApplied];
|
|
113
|
+
// TODO: investigating refactoring so that this is no longer necessary, as we have had genuine bugs with missed deps.
|
|
114
|
+
// See https://github.com/clockworklabs/SpacetimeDB/pull/4580.
|
|
107
115
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
-
}, [connectionState, accessorName, querySql, subscribeApplied]);
|
|
116
|
+
}, [connectionState, accessorName, querySql, subscribeApplied, enabled]);
|
|
109
117
|
|
|
110
118
|
// Invalidate the cached snapshot when computeSnapshot changes (e.g. when
|
|
111
119
|
// subscribeApplied flips to true) so getSnapshot() recomputes on the next
|
|
@@ -115,6 +123,10 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
115
123
|
}, [computeSnapshot]);
|
|
116
124
|
|
|
117
125
|
useEffect(() => {
|
|
126
|
+
if (!enabled) {
|
|
127
|
+
setSubscribeApplied(false);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
118
130
|
const connection = connectionState.getConnection()!;
|
|
119
131
|
if (connectionState.isActive && connection) {
|
|
120
132
|
const cancel = connection
|
|
@@ -127,10 +139,14 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
127
139
|
cancel.unsubscribe();
|
|
128
140
|
};
|
|
129
141
|
}
|
|
130
|
-
}, [querySql, connectionState.isActive, connectionState]);
|
|
142
|
+
}, [querySql, connectionState.isActive, connectionState, enabled]);
|
|
131
143
|
|
|
132
144
|
const subscribe = useCallback(
|
|
133
145
|
(onStoreChange: () => void) => {
|
|
146
|
+
if (!enabled) {
|
|
147
|
+
return () => {};
|
|
148
|
+
}
|
|
149
|
+
|
|
134
150
|
const onInsert = (
|
|
135
151
|
ctx: EventContextInterface<UntypedRemoteModule>,
|
|
136
152
|
row: any
|
|
@@ -205,14 +221,18 @@ export function useTable<TableDef extends UntypedTableDef>(
|
|
|
205
221
|
table.removeOnUpdate?.(onUpdate);
|
|
206
222
|
};
|
|
207
223
|
},
|
|
224
|
+
// TODO: investigating refactoring so that this is no longer necessary, as we have had genuine bugs with missed deps.
|
|
225
|
+
// See https://github.com/clockworklabs/SpacetimeDB/pull/4580.
|
|
208
226
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
209
227
|
[
|
|
210
228
|
connectionState,
|
|
211
229
|
accessorName,
|
|
212
230
|
querySql,
|
|
231
|
+
computeSnapshot,
|
|
213
232
|
callbacks?.onDelete,
|
|
214
233
|
callbacks?.onInsert,
|
|
215
234
|
callbacks?.onUpdate,
|
|
235
|
+
enabled,
|
|
216
236
|
]
|
|
217
237
|
);
|
|
218
238
|
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
} from '../';
|
|
9
9
|
import { ensureMinimumVersionOrThrow } from './version';
|
|
10
10
|
import { WebsocketDecompressAdapter } from './websocket_decompress_adapter';
|
|
11
|
+
import type { WebSocketFactory } from './ws';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The database client connection to a SpacetimeDB server.
|
|
@@ -23,10 +24,10 @@ export class DbConnectionBuilder<DbConnection extends DbConnectionImpl<any>> {
|
|
|
23
24
|
#identity?: Identity;
|
|
24
25
|
#token?: string;
|
|
25
26
|
#emitter: EventEmitter<ConnectionEvent> = new EventEmitter();
|
|
26
|
-
#compression: 'gzip' | 'none' = 'gzip';
|
|
27
|
+
#compression: 'gzip' | 'brotli' | 'none' = 'gzip';
|
|
27
28
|
#lightMode: boolean = false;
|
|
28
29
|
#confirmedReads?: boolean;
|
|
29
|
-
#createWSFn:
|
|
30
|
+
#createWSFn: WebSocketFactory;
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* Creates a new `DbConnectionBuilder` database client and set the initial parameters.
|
|
@@ -42,7 +43,7 @@ export class DbConnectionBuilder<DbConnection extends DbConnectionImpl<any>> {
|
|
|
42
43
|
config: DbConnectionConfig<RemoteModuleOf<DbConnection>>
|
|
43
44
|
) => DbConnection
|
|
44
45
|
) {
|
|
45
|
-
this.#createWSFn = WebsocketDecompressAdapter.
|
|
46
|
+
this.#createWSFn = WebsocketDecompressAdapter.openWebSocket;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/**
|
|
@@ -82,9 +83,7 @@ export class DbConnectionBuilder<DbConnection extends DbConnectionImpl<any>> {
|
|
|
82
83
|
return this;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
withWSFn(
|
|
86
|
-
createWSFn: typeof WebsocketDecompressAdapter.createWebSocketFn
|
|
87
|
-
): this {
|
|
86
|
+
withWSFn(createWSFn: WebSocketFactory): this {
|
|
88
87
|
this.#createWSFn = createWSFn;
|
|
89
88
|
return this;
|
|
90
89
|
}
|
|
@@ -94,7 +93,17 @@ export class DbConnectionBuilder<DbConnection extends DbConnectionImpl<any>> {
|
|
|
94
93
|
*
|
|
95
94
|
* @param compression The compression algorithm to use for the connection.
|
|
96
95
|
*/
|
|
97
|
-
withCompression(compression: 'gzip' | 'none'): this {
|
|
96
|
+
withCompression(compression: 'gzip' | 'brotli' | 'none'): this {
|
|
97
|
+
if (compression === 'brotli') {
|
|
98
|
+
try {
|
|
99
|
+
new DecompressionStream('brotli' as CompressionFormat);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
throw new TypeError(
|
|
102
|
+
`Brotli compression is not supported by the runtime. Please choose a different compression method.`,
|
|
103
|
+
{ cause: e }
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
98
107
|
this.#compression = compression;
|
|
99
108
|
return this;
|
|
100
109
|
}
|