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