spacetimedb 2.0.3 → 2.0.4
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 +3 -0
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.mjs +3 -0
- package/dist/angular/index.mjs.map +1 -1
- package/dist/browser/angular/index.mjs +3 -0
- package/dist/browser/angular/index.mjs.map +1 -1
- package/dist/browser/react/index.mjs +3 -0
- package/dist/browser/react/index.mjs.map +1 -1
- package/dist/browser/svelte/index.mjs +3 -0
- package/dist/browser/svelte/index.mjs.map +1 -1
- package/dist/browser/vue/index.mjs +3 -0
- package/dist/browser/vue/index.mjs.map +1 -1
- package/dist/index.browser.mjs +126 -92
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +126 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +126 -92
- package/dist/index.mjs.map +1 -1
- package/dist/lib/binary_writer.d.ts +1 -0
- package/dist/lib/binary_writer.d.ts.map +1 -1
- package/dist/lib/indexes.d.ts +1 -1
- package/dist/lib/indexes.d.ts.map +1 -1
- package/dist/lib/query.d.ts +4 -2
- package/dist/lib/query.d.ts.map +1 -1
- package/dist/lib/schema.d.ts +2 -0
- package/dist/lib/schema.d.ts.map +1 -1
- package/dist/lib/table.d.ts +19 -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 +3 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.mjs +3 -0
- package/dist/react/index.mjs.map +1 -1
- package/dist/sdk/db_connection_impl.d.ts.map +1 -1
- package/dist/sdk/index.browser.mjs +126 -92
- package/dist/sdk/index.browser.mjs.map +1 -1
- package/dist/sdk/index.cjs +126 -92
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.mjs +126 -92
- package/dist/sdk/index.mjs.map +1 -1
- package/dist/sdk/table_cache.d.ts.map +1 -1
- package/dist/sdk/websocket_decompress_adapter.d.ts +17 -7
- package/dist/sdk/websocket_decompress_adapter.d.ts.map +1 -1
- package/dist/sdk/websocket_test_adapter.d.ts +3 -2
- package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
- package/dist/server/index.mjs +65 -21
- package/dist/server/index.mjs.map +1 -1
- package/dist/svelte/index.cjs +3 -0
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.mjs +3 -0
- package/dist/svelte/index.mjs.map +1 -1
- package/dist/tanstack/SpacetimeDBQueryClient.d.ts +1 -0
- package/dist/tanstack/SpacetimeDBQueryClient.d.ts.map +1 -1
- package/dist/tanstack/index.cjs +24 -0
- package/dist/tanstack/index.cjs.map +1 -1
- package/dist/tanstack/index.mjs +24 -0
- package/dist/tanstack/index.mjs.map +1 -1
- package/dist/vue/index.cjs +3 -0
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.mjs +3 -0
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/binary_writer.ts +4 -0
- package/src/lib/indexes.ts +1 -1
- package/src/lib/query.ts +30 -6
- package/src/lib/schema.ts +66 -24
- package/src/lib/table.ts +41 -9
- package/src/sdk/db_connection_impl.ts +38 -43
- package/src/sdk/table_cache.ts +14 -11
- package/src/sdk/websocket_decompress_adapter.ts +42 -45
- package/src/sdk/websocket_test_adapter.ts +3 -2
- package/src/server/runtime.ts +7 -3
- package/src/server/schema.test-d.ts +37 -0
- package/src/server/view.test-d.ts +2 -0
- package/src/tanstack/SpacetimeDBQueryClient.ts +24 -0
package/dist/index.browser.mjs
CHANGED
|
@@ -581,6 +581,9 @@ var BinaryWriter = class {
|
|
|
581
581
|
constructor(init) {
|
|
582
582
|
this.buffer = typeof init === "number" ? new ResizableBuffer(init) : init;
|
|
583
583
|
}
|
|
584
|
+
clear() {
|
|
585
|
+
this.offset = 0;
|
|
586
|
+
}
|
|
584
587
|
reset(buffer) {
|
|
585
588
|
this.buffer = buffer;
|
|
586
589
|
this.offset = 0;
|
|
@@ -1628,7 +1631,7 @@ var FromBuilder = class _FromBuilder {
|
|
|
1628
1631
|
}
|
|
1629
1632
|
[QueryBrand] = true;
|
|
1630
1633
|
where(predicate) {
|
|
1631
|
-
const newCondition = predicate(this.table.cols);
|
|
1634
|
+
const newCondition = normalizePredicateExpr(predicate(this.table.cols));
|
|
1632
1635
|
const nextWhere = this.whereClause ? this.whereClause.and(newCondition) : newCondition;
|
|
1633
1636
|
return new _FromBuilder(this.table, nextWhere);
|
|
1634
1637
|
}
|
|
@@ -1805,6 +1808,21 @@ function normalizeValue(val) {
|
|
|
1805
1808
|
}
|
|
1806
1809
|
return literal(val);
|
|
1807
1810
|
}
|
|
1811
|
+
function normalizePredicateExpr(value) {
|
|
1812
|
+
if (value instanceof BooleanExpr) return value;
|
|
1813
|
+
if (typeof value === "boolean") {
|
|
1814
|
+
return new BooleanExpr({
|
|
1815
|
+
type: "eq",
|
|
1816
|
+
left: literal(value),
|
|
1817
|
+
right: literal(true)
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
return new BooleanExpr({
|
|
1821
|
+
type: "eq",
|
|
1822
|
+
left: value,
|
|
1823
|
+
right: literal(true)
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1808
1826
|
var BooleanExpr = class _BooleanExpr {
|
|
1809
1827
|
constructor(data) {
|
|
1810
1828
|
this.data = data;
|
|
@@ -4446,9 +4464,7 @@ var TableCacheImpl = class {
|
|
|
4446
4464
|
this.tableDef = tableDef;
|
|
4447
4465
|
this.rows = /* @__PURE__ */ new Map();
|
|
4448
4466
|
this.emitter = new EventEmitter();
|
|
4449
|
-
const
|
|
4450
|
-
for (const idx of indexesDef) {
|
|
4451
|
-
const idxDef = idx;
|
|
4467
|
+
for (const idxDef of this.tableDef.resolvedIndexes) {
|
|
4452
4468
|
const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
|
|
4453
4469
|
this[idxDef.name] = index;
|
|
4454
4470
|
}
|
|
@@ -5005,37 +5021,39 @@ async function resolveWS() {
|
|
|
5005
5021
|
|
|
5006
5022
|
// src/sdk/websocket_decompress_adapter.ts
|
|
5007
5023
|
var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
5008
|
-
onclose
|
|
5009
|
-
|
|
5010
|
-
onmessage;
|
|
5011
|
-
onerror;
|
|
5012
|
-
#ws;
|
|
5013
|
-
async #handleOnMessage(msg) {
|
|
5014
|
-
const buffer = new Uint8Array(msg.data);
|
|
5015
|
-
let decompressed;
|
|
5016
|
-
if (buffer[0] === 0) {
|
|
5017
|
-
decompressed = buffer.slice(1);
|
|
5018
|
-
} else if (buffer[0] === 1) {
|
|
5019
|
-
throw new Error(
|
|
5020
|
-
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
5021
|
-
);
|
|
5022
|
-
} else if (buffer[0] === 2) {
|
|
5023
|
-
decompressed = await decompress(buffer.slice(1), "gzip");
|
|
5024
|
-
} else {
|
|
5025
|
-
throw new Error(
|
|
5026
|
-
"Unexpected Compression Algorithm. Please use `gzip` or `none`"
|
|
5027
|
-
);
|
|
5028
|
-
}
|
|
5029
|
-
this.onmessage?.({ data: decompressed });
|
|
5024
|
+
set onclose(handler) {
|
|
5025
|
+
this.#ws.onclose = handler;
|
|
5030
5026
|
}
|
|
5031
|
-
|
|
5032
|
-
this.onopen
|
|
5027
|
+
set onopen(handler) {
|
|
5028
|
+
this.#ws.onopen = handler;
|
|
5033
5029
|
}
|
|
5034
|
-
|
|
5035
|
-
this.
|
|
5030
|
+
set onmessage(handler) {
|
|
5031
|
+
this.#ws.onmessage = async (msg) => {
|
|
5032
|
+
const data = await this.#decompress(new Uint8Array(msg.data));
|
|
5033
|
+
handler({ data });
|
|
5034
|
+
};
|
|
5036
5035
|
}
|
|
5037
|
-
|
|
5038
|
-
this.
|
|
5036
|
+
set onerror(handler) {
|
|
5037
|
+
this.#ws.onerror = handler;
|
|
5038
|
+
}
|
|
5039
|
+
#ws;
|
|
5040
|
+
async #decompress(buffer) {
|
|
5041
|
+
const tag = buffer[0];
|
|
5042
|
+
const data = buffer.subarray(1);
|
|
5043
|
+
switch (tag) {
|
|
5044
|
+
case 0:
|
|
5045
|
+
return data;
|
|
5046
|
+
case 1:
|
|
5047
|
+
throw new Error(
|
|
5048
|
+
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
5049
|
+
);
|
|
5050
|
+
case 2:
|
|
5051
|
+
return await decompress(data, "gzip");
|
|
5052
|
+
default:
|
|
5053
|
+
throw new Error(
|
|
5054
|
+
"Unexpected Compression Algorithm. Please use `gzip` or `none`"
|
|
5055
|
+
);
|
|
5056
|
+
}
|
|
5039
5057
|
}
|
|
5040
5058
|
send(msg) {
|
|
5041
5059
|
this.#ws.send(msg);
|
|
@@ -5044,14 +5062,6 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
5044
5062
|
this.#ws.close();
|
|
5045
5063
|
}
|
|
5046
5064
|
constructor(ws) {
|
|
5047
|
-
this.onmessage = void 0;
|
|
5048
|
-
this.onopen = void 0;
|
|
5049
|
-
this.onmessage = void 0;
|
|
5050
|
-
this.onerror = void 0;
|
|
5051
|
-
ws.onmessage = this.#handleOnMessage.bind(this);
|
|
5052
|
-
ws.onerror = this.#handleOnError.bind(this);
|
|
5053
|
-
ws.onclose = this.#handleOnClose.bind(this);
|
|
5054
|
-
ws.onopen = this.#handleOnOpen.bind(this);
|
|
5055
5065
|
ws.binaryType = "arraybuffer";
|
|
5056
5066
|
this.#ws = ws;
|
|
5057
5067
|
}
|
|
@@ -5688,12 +5698,13 @@ var DbConnectionImpl = class {
|
|
|
5688
5698
|
}
|
|
5689
5699
|
#makeReducers(def) {
|
|
5690
5700
|
const out = {};
|
|
5701
|
+
const writer = new BinaryWriter(1024);
|
|
5691
5702
|
for (const reducer of def.reducers) {
|
|
5692
5703
|
const reducerName = reducer.name;
|
|
5693
5704
|
const key = reducer.accessorName;
|
|
5694
5705
|
const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
|
|
5695
5706
|
out[key] = (params) => {
|
|
5696
|
-
|
|
5707
|
+
writer.clear();
|
|
5697
5708
|
serializeArgs(writer, params);
|
|
5698
5709
|
const argsBuffer = writer.getBuffer();
|
|
5699
5710
|
return this.callReducer(reducerName, argsBuffer, params);
|
|
@@ -5703,12 +5714,13 @@ var DbConnectionImpl = class {
|
|
|
5703
5714
|
}
|
|
5704
5715
|
#makeProcedures(def) {
|
|
5705
5716
|
const out = {};
|
|
5717
|
+
const writer = new BinaryWriter(1024);
|
|
5706
5718
|
for (const procedure of def.procedures) {
|
|
5707
5719
|
const procedureName = procedure.name;
|
|
5708
5720
|
const key = procedure.accessorName;
|
|
5709
5721
|
const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
|
|
5710
5722
|
out[key] = (params) => {
|
|
5711
|
-
|
|
5723
|
+
writer.clear();
|
|
5712
5724
|
serializeArgs(writer, params);
|
|
5713
5725
|
const argsBuffer = writer.getBuffer();
|
|
5714
5726
|
return this.callProcedure(procedureName, argsBuffer).then((returnBuf) => {
|
|
@@ -5863,34 +5875,32 @@ var DbConnectionImpl = class {
|
|
|
5863
5875
|
}
|
|
5864
5876
|
return this.#mergeTableUpdates(updates);
|
|
5865
5877
|
}
|
|
5866
|
-
#sendEncoded(wsResolved, message) {
|
|
5867
|
-
stdbLogger(
|
|
5868
|
-
"trace",
|
|
5869
|
-
() => `Sending message to server: ${stringify(message)}`
|
|
5870
|
-
);
|
|
5871
|
-
const writer = new BinaryWriter(1024);
|
|
5872
|
-
ClientMessage.serialize(writer, message);
|
|
5873
|
-
const encoded = writer.getBuffer();
|
|
5874
|
-
wsResolved.send(encoded);
|
|
5875
|
-
}
|
|
5876
5878
|
#flushOutboundQueue(wsResolved) {
|
|
5877
|
-
if (!this.isActive || this.#outboundQueue.length === 0) {
|
|
5878
|
-
return;
|
|
5879
|
-
}
|
|
5880
5879
|
const pending = this.#outboundQueue.splice(0);
|
|
5881
5880
|
for (const message of pending) {
|
|
5882
|
-
|
|
5881
|
+
wsResolved.send(message);
|
|
5883
5882
|
}
|
|
5884
5883
|
}
|
|
5884
|
+
#clientMessageEncoder = new BinaryWriter(1024);
|
|
5885
5885
|
#sendMessage(message) {
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
this.#flushOutboundQueue(
|
|
5892
|
-
|
|
5893
|
-
|
|
5886
|
+
const writer = this.#clientMessageEncoder;
|
|
5887
|
+
writer.clear();
|
|
5888
|
+
ClientMessage.serialize(writer, message);
|
|
5889
|
+
const encoded = writer.getBuffer();
|
|
5890
|
+
if (this.ws && this.isActive) {
|
|
5891
|
+
if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
|
|
5892
|
+
stdbLogger(
|
|
5893
|
+
"trace",
|
|
5894
|
+
() => `Sending message to server: ${stringify(message)}`
|
|
5895
|
+
);
|
|
5896
|
+
this.ws.send(encoded);
|
|
5897
|
+
} else {
|
|
5898
|
+
stdbLogger(
|
|
5899
|
+
"trace",
|
|
5900
|
+
() => `Queuing message to server: ${stringify(message)}`
|
|
5901
|
+
);
|
|
5902
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5903
|
+
}
|
|
5894
5904
|
}
|
|
5895
5905
|
#nextEventId() {
|
|
5896
5906
|
this.#eventId += 1;
|
|
@@ -6232,11 +6242,7 @@ var DbConnectionImpl = class {
|
|
|
6232
6242
|
* ```
|
|
6233
6243
|
*/
|
|
6234
6244
|
disconnect() {
|
|
6235
|
-
this.wsPromise.then((
|
|
6236
|
-
if (wsResolved) {
|
|
6237
|
-
wsResolved.close();
|
|
6238
|
-
}
|
|
6239
|
-
});
|
|
6245
|
+
this.wsPromise.then((ws) => ws?.close());
|
|
6240
6246
|
}
|
|
6241
6247
|
on(eventName, callback) {
|
|
6242
6248
|
this.#emitter.on(eventName, callback);
|
|
@@ -6266,17 +6272,45 @@ var DbConnectionImpl = class {
|
|
|
6266
6272
|
|
|
6267
6273
|
// src/lib/schema.ts
|
|
6268
6274
|
function tablesToSchema(ctx, tables) {
|
|
6275
|
+
const tableDefs = /* @__PURE__ */ Object.create(null);
|
|
6276
|
+
for (const [accName, schema2] of Object.entries(tables)) {
|
|
6277
|
+
tableDefs[accName] = tableToSchema(
|
|
6278
|
+
accName,
|
|
6279
|
+
schema2,
|
|
6280
|
+
schema2.tableDef(ctx, accName)
|
|
6281
|
+
);
|
|
6282
|
+
}
|
|
6269
6283
|
return {
|
|
6270
|
-
tables:
|
|
6271
|
-
Object.entries(tables).map(([accName, schema2]) => [
|
|
6272
|
-
accName,
|
|
6273
|
-
tableToSchema(accName, schema2, schema2.tableDef(ctx, accName))
|
|
6274
|
-
])
|
|
6275
|
-
)
|
|
6284
|
+
tables: tableDefs
|
|
6276
6285
|
};
|
|
6277
6286
|
}
|
|
6278
6287
|
function tableToSchema(accName, schema2, tableDef) {
|
|
6279
6288
|
const getColName = (i) => schema2.rowType.algebraicType.value.elements[i].name;
|
|
6289
|
+
const resolvedIndexes = tableDef.indexes.map(
|
|
6290
|
+
(idx) => {
|
|
6291
|
+
const accessorName = idx.accessorName;
|
|
6292
|
+
if (typeof accessorName !== "string" || accessorName.length === 0) {
|
|
6293
|
+
throw new TypeError(
|
|
6294
|
+
`Index '${idx.sourceName ?? "<unknown>"}' on table '${tableDef.sourceName}' is missing accessor name`
|
|
6295
|
+
);
|
|
6296
|
+
}
|
|
6297
|
+
const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
|
|
6298
|
+
const unique = tableDef.constraints.some(
|
|
6299
|
+
(c) => c.data.tag === "Unique" && c.data.value.columns.every((col) => columnIds.includes(col))
|
|
6300
|
+
);
|
|
6301
|
+
const algorithm = {
|
|
6302
|
+
BTree: "btree",
|
|
6303
|
+
Hash: "hash",
|
|
6304
|
+
Direct: "direct"
|
|
6305
|
+
}[idx.algorithm.tag];
|
|
6306
|
+
return {
|
|
6307
|
+
name: accessorName,
|
|
6308
|
+
unique,
|
|
6309
|
+
algorithm,
|
|
6310
|
+
columns: columnIds.map(getColName)
|
|
6311
|
+
};
|
|
6312
|
+
}
|
|
6313
|
+
);
|
|
6280
6314
|
return {
|
|
6281
6315
|
// For client,`schama.tableName` will always be there as canonical name.
|
|
6282
6316
|
// For module, if explicit name is not provided via `name`, accessor name will
|
|
@@ -6286,26 +6320,16 @@ function tableToSchema(accName, schema2, tableDef) {
|
|
|
6286
6320
|
columns: schema2.rowType.row,
|
|
6287
6321
|
// typed as T[i]['rowType']['row'] under TablesToSchema<T>
|
|
6288
6322
|
rowType: schema2.rowSpacetimeType,
|
|
6323
|
+
// Keep declarative indexes in their original shape for type-level consumers.
|
|
6324
|
+
indexes: schema2.idxs,
|
|
6289
6325
|
constraints: tableDef.constraints.map((c) => ({
|
|
6290
6326
|
name: c.sourceName,
|
|
6291
6327
|
constraint: "unique",
|
|
6292
6328
|
columns: c.data.value.columns.map(getColName)
|
|
6293
6329
|
})),
|
|
6294
|
-
//
|
|
6295
|
-
//
|
|
6296
|
-
|
|
6297
|
-
// We should stop lying about our types.
|
|
6298
|
-
indexes: tableDef.indexes.map((idx) => {
|
|
6299
|
-
const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
|
|
6300
|
-
return {
|
|
6301
|
-
name: idx.accessorName,
|
|
6302
|
-
unique: tableDef.constraints.some(
|
|
6303
|
-
(c) => c.data.value.columns.every((col) => columnIds.includes(col))
|
|
6304
|
-
),
|
|
6305
|
-
algorithm: idx.algorithm.tag.toLowerCase(),
|
|
6306
|
-
columns: columnIds.map(getColName)
|
|
6307
|
-
};
|
|
6308
|
-
}),
|
|
6330
|
+
// Expose resolved runtime indexes separately so runtime users don't have to
|
|
6331
|
+
// reinterpret `indexes` with unsafe casts.
|
|
6332
|
+
resolvedIndexes,
|
|
6309
6333
|
tableDef,
|
|
6310
6334
|
...tableDef.isEvent ? { isEvent: true } : {}
|
|
6311
6335
|
};
|
|
@@ -7129,6 +7153,14 @@ function table(opts, row, ..._) {
|
|
|
7129
7153
|
}
|
|
7130
7154
|
}
|
|
7131
7155
|
for (const indexOpts of userIndexes ?? []) {
|
|
7156
|
+
const accessor = indexOpts.accessor;
|
|
7157
|
+
if (typeof accessor !== "string" || accessor.length === 0) {
|
|
7158
|
+
const tableLabel = name ?? "<unnamed>";
|
|
7159
|
+
const indexLabel = indexOpts.name ?? "<unnamed>";
|
|
7160
|
+
throw new TypeError(
|
|
7161
|
+
`Index '${indexLabel}' on table '${tableLabel}' must define a non-empty 'accessor'`
|
|
7162
|
+
);
|
|
7163
|
+
}
|
|
7132
7164
|
let algorithm;
|
|
7133
7165
|
switch (indexOpts.algorithm) {
|
|
7134
7166
|
case "btree":
|
|
@@ -7149,7 +7181,7 @@ function table(opts, row, ..._) {
|
|
|
7149
7181
|
}
|
|
7150
7182
|
indexes.push({
|
|
7151
7183
|
sourceName: void 0,
|
|
7152
|
-
accessorName:
|
|
7184
|
+
accessorName: accessor,
|
|
7153
7185
|
algorithm,
|
|
7154
7186
|
canonicalName: indexOpts.name
|
|
7155
7187
|
});
|
|
@@ -7199,7 +7231,9 @@ function table(opts, row, ..._) {
|
|
|
7199
7231
|
isEvent
|
|
7200
7232
|
};
|
|
7201
7233
|
},
|
|
7202
|
-
|
|
7234
|
+
// Preserve the declared index options as runtime data so `tableToSchema`
|
|
7235
|
+
// can expose them without type-smuggling.
|
|
7236
|
+
idxs: userIndexes,
|
|
7203
7237
|
constraints,
|
|
7204
7238
|
schedule
|
|
7205
7239
|
};
|