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/sdk/index.cjs
CHANGED
|
@@ -583,6 +583,9 @@ var BinaryWriter = class {
|
|
|
583
583
|
constructor(init) {
|
|
584
584
|
this.buffer = typeof init === "number" ? new ResizableBuffer(init) : init;
|
|
585
585
|
}
|
|
586
|
+
clear() {
|
|
587
|
+
this.offset = 0;
|
|
588
|
+
}
|
|
586
589
|
reset(buffer) {
|
|
587
590
|
this.buffer = buffer;
|
|
588
591
|
this.offset = 0;
|
|
@@ -1577,7 +1580,7 @@ var FromBuilder = class _FromBuilder {
|
|
|
1577
1580
|
}
|
|
1578
1581
|
[QueryBrand] = true;
|
|
1579
1582
|
where(predicate) {
|
|
1580
|
-
const newCondition = predicate(this.table.cols);
|
|
1583
|
+
const newCondition = normalizePredicateExpr(predicate(this.table.cols));
|
|
1581
1584
|
const nextWhere = this.whereClause ? this.whereClause.and(newCondition) : newCondition;
|
|
1582
1585
|
return new _FromBuilder(this.table, nextWhere);
|
|
1583
1586
|
}
|
|
@@ -1754,6 +1757,21 @@ function normalizeValue(val) {
|
|
|
1754
1757
|
}
|
|
1755
1758
|
return literal(val);
|
|
1756
1759
|
}
|
|
1760
|
+
function normalizePredicateExpr(value) {
|
|
1761
|
+
if (value instanceof BooleanExpr) return value;
|
|
1762
|
+
if (typeof value === "boolean") {
|
|
1763
|
+
return new BooleanExpr({
|
|
1764
|
+
type: "eq",
|
|
1765
|
+
left: literal(value),
|
|
1766
|
+
right: literal(true)
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
return new BooleanExpr({
|
|
1770
|
+
type: "eq",
|
|
1771
|
+
left: value,
|
|
1772
|
+
right: literal(true)
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1757
1775
|
var BooleanExpr = class _BooleanExpr {
|
|
1758
1776
|
constructor(data) {
|
|
1759
1777
|
this.data = data;
|
|
@@ -4315,9 +4333,7 @@ var TableCacheImpl = class {
|
|
|
4315
4333
|
this.tableDef = tableDef;
|
|
4316
4334
|
this.rows = /* @__PURE__ */ new Map();
|
|
4317
4335
|
this.emitter = new EventEmitter();
|
|
4318
|
-
const
|
|
4319
|
-
for (const idx of indexesDef) {
|
|
4320
|
-
const idxDef = idx;
|
|
4336
|
+
for (const idxDef of this.tableDef.resolvedIndexes) {
|
|
4321
4337
|
const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
|
|
4322
4338
|
this[idxDef.name] = index;
|
|
4323
4339
|
}
|
|
@@ -4874,37 +4890,39 @@ async function resolveWS() {
|
|
|
4874
4890
|
|
|
4875
4891
|
// src/sdk/websocket_decompress_adapter.ts
|
|
4876
4892
|
var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
4877
|
-
onclose
|
|
4878
|
-
|
|
4879
|
-
onmessage;
|
|
4880
|
-
onerror;
|
|
4881
|
-
#ws;
|
|
4882
|
-
async #handleOnMessage(msg) {
|
|
4883
|
-
const buffer = new Uint8Array(msg.data);
|
|
4884
|
-
let decompressed;
|
|
4885
|
-
if (buffer[0] === 0) {
|
|
4886
|
-
decompressed = buffer.slice(1);
|
|
4887
|
-
} else if (buffer[0] === 1) {
|
|
4888
|
-
throw new Error(
|
|
4889
|
-
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
4890
|
-
);
|
|
4891
|
-
} else if (buffer[0] === 2) {
|
|
4892
|
-
decompressed = await decompress(buffer.slice(1), "gzip");
|
|
4893
|
-
} else {
|
|
4894
|
-
throw new Error(
|
|
4895
|
-
"Unexpected Compression Algorithm. Please use `gzip` or `none`"
|
|
4896
|
-
);
|
|
4897
|
-
}
|
|
4898
|
-
this.onmessage?.({ data: decompressed });
|
|
4893
|
+
set onclose(handler) {
|
|
4894
|
+
this.#ws.onclose = handler;
|
|
4899
4895
|
}
|
|
4900
|
-
|
|
4901
|
-
this.onopen
|
|
4896
|
+
set onopen(handler) {
|
|
4897
|
+
this.#ws.onopen = handler;
|
|
4898
|
+
}
|
|
4899
|
+
set onmessage(handler) {
|
|
4900
|
+
this.#ws.onmessage = async (msg) => {
|
|
4901
|
+
const data = await this.#decompress(new Uint8Array(msg.data));
|
|
4902
|
+
handler({ data });
|
|
4903
|
+
};
|
|
4902
4904
|
}
|
|
4903
|
-
|
|
4904
|
-
this.onerror
|
|
4905
|
+
set onerror(handler) {
|
|
4906
|
+
this.#ws.onerror = handler;
|
|
4905
4907
|
}
|
|
4906
|
-
#
|
|
4907
|
-
|
|
4908
|
+
#ws;
|
|
4909
|
+
async #decompress(buffer) {
|
|
4910
|
+
const tag = buffer[0];
|
|
4911
|
+
const data = buffer.subarray(1);
|
|
4912
|
+
switch (tag) {
|
|
4913
|
+
case 0:
|
|
4914
|
+
return data;
|
|
4915
|
+
case 1:
|
|
4916
|
+
throw new Error(
|
|
4917
|
+
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
4918
|
+
);
|
|
4919
|
+
case 2:
|
|
4920
|
+
return await decompress(data, "gzip");
|
|
4921
|
+
default:
|
|
4922
|
+
throw new Error(
|
|
4923
|
+
"Unexpected Compression Algorithm. Please use `gzip` or `none`"
|
|
4924
|
+
);
|
|
4925
|
+
}
|
|
4908
4926
|
}
|
|
4909
4927
|
send(msg) {
|
|
4910
4928
|
this.#ws.send(msg);
|
|
@@ -4913,14 +4931,6 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
4913
4931
|
this.#ws.close();
|
|
4914
4932
|
}
|
|
4915
4933
|
constructor(ws) {
|
|
4916
|
-
this.onmessage = void 0;
|
|
4917
|
-
this.onopen = void 0;
|
|
4918
|
-
this.onmessage = void 0;
|
|
4919
|
-
this.onerror = void 0;
|
|
4920
|
-
ws.onmessage = this.#handleOnMessage.bind(this);
|
|
4921
|
-
ws.onerror = this.#handleOnError.bind(this);
|
|
4922
|
-
ws.onclose = this.#handleOnClose.bind(this);
|
|
4923
|
-
ws.onopen = this.#handleOnOpen.bind(this);
|
|
4924
4934
|
ws.binaryType = "arraybuffer";
|
|
4925
4935
|
this.#ws = ws;
|
|
4926
4936
|
}
|
|
@@ -5557,12 +5567,13 @@ var DbConnectionImpl = class {
|
|
|
5557
5567
|
}
|
|
5558
5568
|
#makeReducers(def) {
|
|
5559
5569
|
const out = {};
|
|
5570
|
+
const writer = new BinaryWriter(1024);
|
|
5560
5571
|
for (const reducer of def.reducers) {
|
|
5561
5572
|
const reducerName = reducer.name;
|
|
5562
5573
|
const key = reducer.accessorName;
|
|
5563
5574
|
const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
|
|
5564
5575
|
out[key] = (params) => {
|
|
5565
|
-
|
|
5576
|
+
writer.clear();
|
|
5566
5577
|
serializeArgs(writer, params);
|
|
5567
5578
|
const argsBuffer = writer.getBuffer();
|
|
5568
5579
|
return this.callReducer(reducerName, argsBuffer, params);
|
|
@@ -5572,12 +5583,13 @@ var DbConnectionImpl = class {
|
|
|
5572
5583
|
}
|
|
5573
5584
|
#makeProcedures(def) {
|
|
5574
5585
|
const out = {};
|
|
5586
|
+
const writer = new BinaryWriter(1024);
|
|
5575
5587
|
for (const procedure of def.procedures) {
|
|
5576
5588
|
const procedureName = procedure.name;
|
|
5577
5589
|
const key = procedure.accessorName;
|
|
5578
5590
|
const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
|
|
5579
5591
|
out[key] = (params) => {
|
|
5580
|
-
|
|
5592
|
+
writer.clear();
|
|
5581
5593
|
serializeArgs(writer, params);
|
|
5582
5594
|
const argsBuffer = writer.getBuffer();
|
|
5583
5595
|
return this.callProcedure(procedureName, argsBuffer).then((returnBuf) => {
|
|
@@ -5732,34 +5744,32 @@ var DbConnectionImpl = class {
|
|
|
5732
5744
|
}
|
|
5733
5745
|
return this.#mergeTableUpdates(updates);
|
|
5734
5746
|
}
|
|
5735
|
-
#sendEncoded(wsResolved, message) {
|
|
5736
|
-
stdbLogger(
|
|
5737
|
-
"trace",
|
|
5738
|
-
() => `Sending message to server: ${stringify(message)}`
|
|
5739
|
-
);
|
|
5740
|
-
const writer = new BinaryWriter(1024);
|
|
5741
|
-
ClientMessage.serialize(writer, message);
|
|
5742
|
-
const encoded = writer.getBuffer();
|
|
5743
|
-
wsResolved.send(encoded);
|
|
5744
|
-
}
|
|
5745
5747
|
#flushOutboundQueue(wsResolved) {
|
|
5746
|
-
if (!this.isActive || this.#outboundQueue.length === 0) {
|
|
5747
|
-
return;
|
|
5748
|
-
}
|
|
5749
5748
|
const pending = this.#outboundQueue.splice(0);
|
|
5750
5749
|
for (const message of pending) {
|
|
5751
|
-
|
|
5750
|
+
wsResolved.send(message);
|
|
5752
5751
|
}
|
|
5753
5752
|
}
|
|
5753
|
+
#clientMessageEncoder = new BinaryWriter(1024);
|
|
5754
5754
|
#sendMessage(message) {
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
this.#flushOutboundQueue(
|
|
5761
|
-
|
|
5762
|
-
|
|
5755
|
+
const writer = this.#clientMessageEncoder;
|
|
5756
|
+
writer.clear();
|
|
5757
|
+
ClientMessage.serialize(writer, message);
|
|
5758
|
+
const encoded = writer.getBuffer();
|
|
5759
|
+
if (this.ws && this.isActive) {
|
|
5760
|
+
if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
|
|
5761
|
+
stdbLogger(
|
|
5762
|
+
"trace",
|
|
5763
|
+
() => `Sending message to server: ${stringify(message)}`
|
|
5764
|
+
);
|
|
5765
|
+
this.ws.send(encoded);
|
|
5766
|
+
} else {
|
|
5767
|
+
stdbLogger(
|
|
5768
|
+
"trace",
|
|
5769
|
+
() => `Queuing message to server: ${stringify(message)}`
|
|
5770
|
+
);
|
|
5771
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5772
|
+
}
|
|
5763
5773
|
}
|
|
5764
5774
|
#nextEventId() {
|
|
5765
5775
|
this.#eventId += 1;
|
|
@@ -6101,11 +6111,7 @@ var DbConnectionImpl = class {
|
|
|
6101
6111
|
* ```
|
|
6102
6112
|
*/
|
|
6103
6113
|
disconnect() {
|
|
6104
|
-
this.wsPromise.then((
|
|
6105
|
-
if (wsResolved) {
|
|
6106
|
-
wsResolved.close();
|
|
6107
|
-
}
|
|
6108
|
-
});
|
|
6114
|
+
this.wsPromise.then((ws) => ws?.close());
|
|
6109
6115
|
}
|
|
6110
6116
|
on(eventName, callback) {
|
|
6111
6117
|
this.#emitter.on(eventName, callback);
|
|
@@ -6135,17 +6141,45 @@ var DbConnectionImpl = class {
|
|
|
6135
6141
|
|
|
6136
6142
|
// src/lib/schema.ts
|
|
6137
6143
|
function tablesToSchema(ctx, tables) {
|
|
6144
|
+
const tableDefs = /* @__PURE__ */ Object.create(null);
|
|
6145
|
+
for (const [accName, schema2] of Object.entries(tables)) {
|
|
6146
|
+
tableDefs[accName] = tableToSchema(
|
|
6147
|
+
accName,
|
|
6148
|
+
schema2,
|
|
6149
|
+
schema2.tableDef(ctx, accName)
|
|
6150
|
+
);
|
|
6151
|
+
}
|
|
6138
6152
|
return {
|
|
6139
|
-
tables:
|
|
6140
|
-
Object.entries(tables).map(([accName, schema2]) => [
|
|
6141
|
-
accName,
|
|
6142
|
-
tableToSchema(accName, schema2, schema2.tableDef(ctx, accName))
|
|
6143
|
-
])
|
|
6144
|
-
)
|
|
6153
|
+
tables: tableDefs
|
|
6145
6154
|
};
|
|
6146
6155
|
}
|
|
6147
6156
|
function tableToSchema(accName, schema2, tableDef) {
|
|
6148
6157
|
const getColName = (i) => schema2.rowType.algebraicType.value.elements[i].name;
|
|
6158
|
+
const resolvedIndexes = tableDef.indexes.map(
|
|
6159
|
+
(idx) => {
|
|
6160
|
+
const accessorName = idx.accessorName;
|
|
6161
|
+
if (typeof accessorName !== "string" || accessorName.length === 0) {
|
|
6162
|
+
throw new TypeError(
|
|
6163
|
+
`Index '${idx.sourceName ?? "<unknown>"}' on table '${tableDef.sourceName}' is missing accessor name`
|
|
6164
|
+
);
|
|
6165
|
+
}
|
|
6166
|
+
const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
|
|
6167
|
+
const unique = tableDef.constraints.some(
|
|
6168
|
+
(c) => c.data.tag === "Unique" && c.data.value.columns.every((col) => columnIds.includes(col))
|
|
6169
|
+
);
|
|
6170
|
+
const algorithm = {
|
|
6171
|
+
BTree: "btree",
|
|
6172
|
+
Hash: "hash",
|
|
6173
|
+
Direct: "direct"
|
|
6174
|
+
}[idx.algorithm.tag];
|
|
6175
|
+
return {
|
|
6176
|
+
name: accessorName,
|
|
6177
|
+
unique,
|
|
6178
|
+
algorithm,
|
|
6179
|
+
columns: columnIds.map(getColName)
|
|
6180
|
+
};
|
|
6181
|
+
}
|
|
6182
|
+
);
|
|
6149
6183
|
return {
|
|
6150
6184
|
// For client,`schama.tableName` will always be there as canonical name.
|
|
6151
6185
|
// For module, if explicit name is not provided via `name`, accessor name will
|
|
@@ -6155,26 +6189,16 @@ function tableToSchema(accName, schema2, tableDef) {
|
|
|
6155
6189
|
columns: schema2.rowType.row,
|
|
6156
6190
|
// typed as T[i]['rowType']['row'] under TablesToSchema<T>
|
|
6157
6191
|
rowType: schema2.rowSpacetimeType,
|
|
6192
|
+
// Keep declarative indexes in their original shape for type-level consumers.
|
|
6193
|
+
indexes: schema2.idxs,
|
|
6158
6194
|
constraints: tableDef.constraints.map((c) => ({
|
|
6159
6195
|
name: c.sourceName,
|
|
6160
6196
|
constraint: "unique",
|
|
6161
6197
|
columns: c.data.value.columns.map(getColName)
|
|
6162
6198
|
})),
|
|
6163
|
-
//
|
|
6164
|
-
//
|
|
6165
|
-
|
|
6166
|
-
// We should stop lying about our types.
|
|
6167
|
-
indexes: tableDef.indexes.map((idx) => {
|
|
6168
|
-
const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
|
|
6169
|
-
return {
|
|
6170
|
-
name: idx.accessorName,
|
|
6171
|
-
unique: tableDef.constraints.some(
|
|
6172
|
-
(c) => c.data.value.columns.every((col) => columnIds.includes(col))
|
|
6173
|
-
),
|
|
6174
|
-
algorithm: idx.algorithm.tag.toLowerCase(),
|
|
6175
|
-
columns: columnIds.map(getColName)
|
|
6176
|
-
};
|
|
6177
|
-
}),
|
|
6199
|
+
// Expose resolved runtime indexes separately so runtime users don't have to
|
|
6200
|
+
// reinterpret `indexes` with unsafe casts.
|
|
6201
|
+
resolvedIndexes,
|
|
6178
6202
|
tableDef,
|
|
6179
6203
|
...tableDef.isEvent ? { isEvent: true } : {}
|
|
6180
6204
|
};
|
|
@@ -6998,6 +7022,14 @@ function table(opts, row, ..._) {
|
|
|
6998
7022
|
}
|
|
6999
7023
|
}
|
|
7000
7024
|
for (const indexOpts of userIndexes ?? []) {
|
|
7025
|
+
const accessor = indexOpts.accessor;
|
|
7026
|
+
if (typeof accessor !== "string" || accessor.length === 0) {
|
|
7027
|
+
const tableLabel = name ?? "<unnamed>";
|
|
7028
|
+
const indexLabel = indexOpts.name ?? "<unnamed>";
|
|
7029
|
+
throw new TypeError(
|
|
7030
|
+
`Index '${indexLabel}' on table '${tableLabel}' must define a non-empty 'accessor'`
|
|
7031
|
+
);
|
|
7032
|
+
}
|
|
7001
7033
|
let algorithm;
|
|
7002
7034
|
switch (indexOpts.algorithm) {
|
|
7003
7035
|
case "btree":
|
|
@@ -7018,7 +7050,7 @@ function table(opts, row, ..._) {
|
|
|
7018
7050
|
}
|
|
7019
7051
|
indexes.push({
|
|
7020
7052
|
sourceName: void 0,
|
|
7021
|
-
accessorName:
|
|
7053
|
+
accessorName: accessor,
|
|
7022
7054
|
algorithm,
|
|
7023
7055
|
canonicalName: indexOpts.name
|
|
7024
7056
|
});
|
|
@@ -7068,7 +7100,9 @@ function table(opts, row, ..._) {
|
|
|
7068
7100
|
isEvent
|
|
7069
7101
|
};
|
|
7070
7102
|
},
|
|
7071
|
-
|
|
7103
|
+
// Preserve the declared index options as runtime data so `tableToSchema`
|
|
7104
|
+
// can expose them without type-smuggling.
|
|
7105
|
+
idxs: userIndexes,
|
|
7072
7106
|
constraints,
|
|
7073
7107
|
schedule
|
|
7074
7108
|
};
|