spacetimedb 2.0.2 → 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.
Files changed (95) hide show
  1. package/LICENSE.txt +2 -2
  2. package/dist/angular/index.cjs +3 -0
  3. package/dist/angular/index.cjs.map +1 -1
  4. package/dist/angular/index.mjs +3 -0
  5. package/dist/angular/index.mjs.map +1 -1
  6. package/dist/browser/angular/index.mjs +3 -0
  7. package/dist/browser/angular/index.mjs.map +1 -1
  8. package/dist/browser/react/index.mjs +6 -0
  9. package/dist/browser/react/index.mjs.map +1 -1
  10. package/dist/browser/svelte/index.mjs +3 -0
  11. package/dist/browser/svelte/index.mjs.map +1 -1
  12. package/dist/browser/vue/index.mjs +3 -0
  13. package/dist/browser/vue/index.mjs.map +1 -1
  14. package/dist/index.browser.mjs +133 -100
  15. package/dist/index.browser.mjs.map +1 -1
  16. package/dist/index.cjs +133 -100
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +133 -100
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/lib/binary_writer.d.ts +1 -0
  21. package/dist/lib/binary_writer.d.ts.map +1 -1
  22. package/dist/lib/indexes.d.ts +1 -1
  23. package/dist/lib/indexes.d.ts.map +1 -1
  24. package/dist/lib/query.d.ts +4 -2
  25. package/dist/lib/query.d.ts.map +1 -1
  26. package/dist/lib/schema.d.ts +2 -0
  27. package/dist/lib/schema.d.ts.map +1 -1
  28. package/dist/lib/table.d.ts +19 -1
  29. package/dist/lib/table.d.ts.map +1 -1
  30. package/dist/lib/util.d.ts +11 -11
  31. package/dist/lib/util.d.ts.map +1 -1
  32. package/dist/min/index.browser.mjs +1 -1
  33. package/dist/min/index.browser.mjs.map +1 -1
  34. package/dist/min/react/index.mjs +1 -1
  35. package/dist/min/react/index.mjs.map +1 -1
  36. package/dist/min/sdk/index.browser.mjs +1 -1
  37. package/dist/min/sdk/index.browser.mjs.map +1 -1
  38. package/dist/react/index.cjs +6 -0
  39. package/dist/react/index.cjs.map +1 -1
  40. package/dist/react/index.mjs +6 -0
  41. package/dist/react/index.mjs.map +1 -1
  42. package/dist/react/useTable.d.ts.map +1 -1
  43. package/dist/sdk/db_connection_impl.d.ts.map +1 -1
  44. package/dist/sdk/index.browser.mjs +133 -100
  45. package/dist/sdk/index.browser.mjs.map +1 -1
  46. package/dist/sdk/index.cjs +133 -100
  47. package/dist/sdk/index.cjs.map +1 -1
  48. package/dist/sdk/index.mjs +133 -100
  49. package/dist/sdk/index.mjs.map +1 -1
  50. package/dist/sdk/procedures.d.ts +1 -1
  51. package/dist/sdk/procedures.d.ts.map +1 -1
  52. package/dist/sdk/reducers.d.ts +2 -3
  53. package/dist/sdk/reducers.d.ts.map +1 -1
  54. package/dist/sdk/table_cache.d.ts.map +1 -1
  55. package/dist/sdk/websocket_decompress_adapter.d.ts +17 -7
  56. package/dist/sdk/websocket_decompress_adapter.d.ts.map +1 -1
  57. package/dist/sdk/websocket_test_adapter.d.ts +3 -2
  58. package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
  59. package/dist/server/index.mjs +72 -29
  60. package/dist/server/index.mjs.map +1 -1
  61. package/dist/svelte/index.cjs +3 -0
  62. package/dist/svelte/index.cjs.map +1 -1
  63. package/dist/svelte/index.mjs +3 -0
  64. package/dist/svelte/index.mjs.map +1 -1
  65. package/dist/tanstack/SpacetimeDBQueryClient.d.ts +3 -3
  66. package/dist/tanstack/SpacetimeDBQueryClient.d.ts.map +1 -1
  67. package/dist/tanstack/hooks.d.ts +3 -6
  68. package/dist/tanstack/hooks.d.ts.map +1 -1
  69. package/dist/tanstack/index.cjs +28 -1
  70. package/dist/tanstack/index.cjs.map +1 -1
  71. package/dist/tanstack/index.mjs +28 -1
  72. package/dist/tanstack/index.mjs.map +1 -1
  73. package/dist/vue/index.cjs +3 -0
  74. package/dist/vue/index.cjs.map +1 -1
  75. package/dist/vue/index.mjs +3 -0
  76. package/dist/vue/index.mjs.map +1 -1
  77. package/package.json +1 -1
  78. package/src/lib/binary_writer.ts +4 -0
  79. package/src/lib/indexes.ts +1 -1
  80. package/src/lib/query.ts +30 -6
  81. package/src/lib/schema.ts +66 -24
  82. package/src/lib/table.ts +41 -9
  83. package/src/lib/util.ts +18 -21
  84. package/src/react/useTable.ts +7 -0
  85. package/src/sdk/db_connection_impl.ts +38 -43
  86. package/src/sdk/procedures.ts +1 -3
  87. package/src/sdk/reducers.ts +5 -7
  88. package/src/sdk/table_cache.ts +14 -11
  89. package/src/sdk/websocket_decompress_adapter.ts +42 -45
  90. package/src/sdk/websocket_test_adapter.ts +3 -2
  91. package/src/server/runtime.ts +7 -3
  92. package/src/server/schema.test-d.ts +37 -0
  93. package/src/server/view.test-d.ts +2 -0
  94. package/src/tanstack/SpacetimeDBQueryClient.ts +28 -2
  95. package/src/tanstack/hooks.ts +3 -2
@@ -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;
@@ -720,12 +723,6 @@ var BinaryWriter = class {
720
723
  };
721
724
 
722
725
  // src/lib/util.ts
723
- function toPascalCase(s) {
724
- const str = s.replace(/([-_][a-z])/gi, ($1) => {
725
- return $1.toUpperCase().replace("-", "").replace("_", "");
726
- });
727
- return str.charAt(0).toUpperCase() + str.slice(1);
728
- }
729
726
  function deepEqual(obj1, obj2) {
730
727
  if (obj1 === obj2) return true;
731
728
  if (typeof obj1 !== "object" || obj1 === null || typeof obj2 !== "object" || obj2 === null) {
@@ -788,8 +785,13 @@ function u256ToUint8Array(data) {
788
785
  function u256ToHexString(data) {
789
786
  return uint8ArrayToHexString(u256ToUint8Array(data));
790
787
  }
791
- function toCamelCase(str) {
792
- return str.replace(/[-_]+/g, "_").replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase());
788
+ function toPascalCase(s) {
789
+ const str = toCamelCase(s);
790
+ return str.charAt(0).toUpperCase() + str.slice(1);
791
+ }
792
+ function toCamelCase(s) {
793
+ const str = s.replace(/[-_]+/g, "_").replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase());
794
+ return str.charAt(0).toLowerCase() + str.slice(1);
793
795
  }
794
796
  function coerceParams(params) {
795
797
  return Object.fromEntries(
@@ -1578,7 +1580,7 @@ var FromBuilder = class _FromBuilder {
1578
1580
  }
1579
1581
  [QueryBrand] = true;
1580
1582
  where(predicate) {
1581
- const newCondition = predicate(this.table.cols);
1583
+ const newCondition = normalizePredicateExpr(predicate(this.table.cols));
1582
1584
  const nextWhere = this.whereClause ? this.whereClause.and(newCondition) : newCondition;
1583
1585
  return new _FromBuilder(this.table, nextWhere);
1584
1586
  }
@@ -1755,6 +1757,21 @@ function normalizeValue(val) {
1755
1757
  }
1756
1758
  return literal(val);
1757
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
+ }
1758
1775
  var BooleanExpr = class _BooleanExpr {
1759
1776
  constructor(data) {
1760
1777
  this.data = data;
@@ -4316,9 +4333,7 @@ var TableCacheImpl = class {
4316
4333
  this.tableDef = tableDef;
4317
4334
  this.rows = /* @__PURE__ */ new Map();
4318
4335
  this.emitter = new EventEmitter();
4319
- const indexesDef = this.tableDef.indexes || [];
4320
- for (const idx of indexesDef) {
4321
- const idxDef = idx;
4336
+ for (const idxDef of this.tableDef.resolvedIndexes) {
4322
4337
  const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
4323
4338
  this[idxDef.name] = index;
4324
4339
  }
@@ -4875,37 +4890,39 @@ async function resolveWS() {
4875
4890
 
4876
4891
  // src/sdk/websocket_decompress_adapter.ts
4877
4892
  var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
4878
- onclose;
4879
- onopen;
4880
- onmessage;
4881
- onerror;
4882
- #ws;
4883
- async #handleOnMessage(msg) {
4884
- const buffer = new Uint8Array(msg.data);
4885
- let decompressed;
4886
- if (buffer[0] === 0) {
4887
- decompressed = buffer.slice(1);
4888
- } else if (buffer[0] === 1) {
4889
- throw new Error(
4890
- "Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
4891
- );
4892
- } else if (buffer[0] === 2) {
4893
- decompressed = await decompress(buffer.slice(1), "gzip");
4894
- } else {
4895
- throw new Error(
4896
- "Unexpected Compression Algorithm. Please use `gzip` or `none`"
4897
- );
4898
- }
4899
- this.onmessage?.({ data: decompressed });
4893
+ set onclose(handler) {
4894
+ this.#ws.onclose = handler;
4900
4895
  }
4901
- #handleOnOpen(msg) {
4902
- this.onopen?.(msg);
4896
+ set onopen(handler) {
4897
+ this.#ws.onopen = handler;
4903
4898
  }
4904
- #handleOnError(msg) {
4905
- this.onerror?.(msg);
4899
+ set onmessage(handler) {
4900
+ this.#ws.onmessage = async (msg) => {
4901
+ const data = await this.#decompress(new Uint8Array(msg.data));
4902
+ handler({ data });
4903
+ };
4906
4904
  }
4907
- #handleOnClose(msg) {
4908
- this.onclose?.(msg);
4905
+ set onerror(handler) {
4906
+ this.#ws.onerror = handler;
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
+ }
4909
4926
  }
4910
4927
  send(msg) {
4911
4928
  this.#ws.send(msg);
@@ -4914,14 +4931,6 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
4914
4931
  this.#ws.close();
4915
4932
  }
4916
4933
  constructor(ws) {
4917
- this.onmessage = void 0;
4918
- this.onopen = void 0;
4919
- this.onmessage = void 0;
4920
- this.onerror = void 0;
4921
- ws.onmessage = this.#handleOnMessage.bind(this);
4922
- ws.onerror = this.#handleOnError.bind(this);
4923
- ws.onclose = this.#handleOnClose.bind(this);
4924
- ws.onopen = this.#handleOnOpen.bind(this);
4925
4934
  ws.binaryType = "arraybuffer";
4926
4935
  this.#ws = ws;
4927
4936
  }
@@ -5558,12 +5567,13 @@ var DbConnectionImpl = class {
5558
5567
  }
5559
5568
  #makeReducers(def) {
5560
5569
  const out = {};
5570
+ const writer = new BinaryWriter(1024);
5561
5571
  for (const reducer of def.reducers) {
5562
5572
  const reducerName = reducer.name;
5563
5573
  const key = reducer.accessorName;
5564
5574
  const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
5565
5575
  out[key] = (params) => {
5566
- const writer = new BinaryWriter(1024);
5576
+ writer.clear();
5567
5577
  serializeArgs(writer, params);
5568
5578
  const argsBuffer = writer.getBuffer();
5569
5579
  return this.callReducer(reducerName, argsBuffer, params);
@@ -5573,12 +5583,13 @@ var DbConnectionImpl = class {
5573
5583
  }
5574
5584
  #makeProcedures(def) {
5575
5585
  const out = {};
5586
+ const writer = new BinaryWriter(1024);
5576
5587
  for (const procedure of def.procedures) {
5577
5588
  const procedureName = procedure.name;
5578
5589
  const key = procedure.accessorName;
5579
5590
  const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
5580
5591
  out[key] = (params) => {
5581
- const writer = new BinaryWriter(1024);
5592
+ writer.clear();
5582
5593
  serializeArgs(writer, params);
5583
5594
  const argsBuffer = writer.getBuffer();
5584
5595
  return this.callProcedure(procedureName, argsBuffer).then((returnBuf) => {
@@ -5733,34 +5744,32 @@ var DbConnectionImpl = class {
5733
5744
  }
5734
5745
  return this.#mergeTableUpdates(updates);
5735
5746
  }
5736
- #sendEncoded(wsResolved, message) {
5737
- stdbLogger(
5738
- "trace",
5739
- () => `Sending message to server: ${stringify(message)}`
5740
- );
5741
- const writer = new BinaryWriter(1024);
5742
- ClientMessage.serialize(writer, message);
5743
- const encoded = writer.getBuffer();
5744
- wsResolved.send(encoded);
5745
- }
5746
5747
  #flushOutboundQueue(wsResolved) {
5747
- if (!this.isActive || this.#outboundQueue.length === 0) {
5748
- return;
5749
- }
5750
5748
  const pending = this.#outboundQueue.splice(0);
5751
5749
  for (const message of pending) {
5752
- this.#sendEncoded(wsResolved, message);
5750
+ wsResolved.send(message);
5753
5751
  }
5754
5752
  }
5753
+ #clientMessageEncoder = new BinaryWriter(1024);
5755
5754
  #sendMessage(message) {
5756
- this.wsPromise.then((wsResolved) => {
5757
- if (!wsResolved || !this.isActive) {
5758
- this.#outboundQueue.push(message);
5759
- return;
5760
- }
5761
- this.#flushOutboundQueue(wsResolved);
5762
- this.#sendEncoded(wsResolved, message);
5763
- });
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
+ }
5764
5773
  }
5765
5774
  #nextEventId() {
5766
5775
  this.#eventId += 1;
@@ -6102,11 +6111,7 @@ var DbConnectionImpl = class {
6102
6111
  * ```
6103
6112
  */
6104
6113
  disconnect() {
6105
- this.wsPromise.then((wsResolved) => {
6106
- if (wsResolved) {
6107
- wsResolved.close();
6108
- }
6109
- });
6114
+ this.wsPromise.then((ws) => ws?.close());
6110
6115
  }
6111
6116
  on(eventName, callback) {
6112
6117
  this.#emitter.on(eventName, callback);
@@ -6136,17 +6141,45 @@ var DbConnectionImpl = class {
6136
6141
 
6137
6142
  // src/lib/schema.ts
6138
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
+ }
6139
6152
  return {
6140
- tables: Object.fromEntries(
6141
- Object.entries(tables).map(([accName, schema2]) => [
6142
- accName,
6143
- tableToSchema(accName, schema2, schema2.tableDef(ctx, accName))
6144
- ])
6145
- )
6153
+ tables: tableDefs
6146
6154
  };
6147
6155
  }
6148
6156
  function tableToSchema(accName, schema2, tableDef) {
6149
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
+ );
6150
6183
  return {
6151
6184
  // For client,`schama.tableName` will always be there as canonical name.
6152
6185
  // For module, if explicit name is not provided via `name`, accessor name will
@@ -6156,26 +6189,16 @@ function tableToSchema(accName, schema2, tableDef) {
6156
6189
  columns: schema2.rowType.row,
6157
6190
  // typed as T[i]['rowType']['row'] under TablesToSchema<T>
6158
6191
  rowType: schema2.rowSpacetimeType,
6192
+ // Keep declarative indexes in their original shape for type-level consumers.
6193
+ indexes: schema2.idxs,
6159
6194
  constraints: tableDef.constraints.map((c) => ({
6160
6195
  name: c.sourceName,
6161
6196
  constraint: "unique",
6162
6197
  columns: c.data.value.columns.map(getColName)
6163
6198
  })),
6164
- // TODO: horrible horrible horrible. we smuggle this `Array<UntypedIndex>`
6165
- // by casting it to an `Array<IndexOpts>` as `TableToSchema` expects.
6166
- // This is then used in `TableCacheImpl.constructor` and who knows where else.
6167
- // We should stop lying about our types.
6168
- indexes: tableDef.indexes.map((idx) => {
6169
- const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
6170
- return {
6171
- name: idx.accessorName,
6172
- unique: tableDef.constraints.some(
6173
- (c) => c.data.value.columns.every((col) => columnIds.includes(col))
6174
- ),
6175
- algorithm: idx.algorithm.tag.toLowerCase(),
6176
- columns: columnIds.map(getColName)
6177
- };
6178
- }),
6199
+ // Expose resolved runtime indexes separately so runtime users don't have to
6200
+ // reinterpret `indexes` with unsafe casts.
6201
+ resolvedIndexes,
6179
6202
  tableDef,
6180
6203
  ...tableDef.isEvent ? { isEvent: true } : {}
6181
6204
  };
@@ -6999,6 +7022,14 @@ function table(opts, row, ..._) {
6999
7022
  }
7000
7023
  }
7001
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
+ }
7002
7033
  let algorithm;
7003
7034
  switch (indexOpts.algorithm) {
7004
7035
  case "btree":
@@ -7019,7 +7050,7 @@ function table(opts, row, ..._) {
7019
7050
  }
7020
7051
  indexes.push({
7021
7052
  sourceName: void 0,
7022
- accessorName: indexOpts.accessor,
7053
+ accessorName: accessor,
7023
7054
  algorithm,
7024
7055
  canonicalName: indexOpts.name
7025
7056
  });
@@ -7069,7 +7100,9 @@ function table(opts, row, ..._) {
7069
7100
  isEvent
7070
7101
  };
7071
7102
  },
7072
- idxs: {},
7103
+ // Preserve the declared index options as runtime data so `tableToSchema`
7104
+ // can expose them without type-smuggling.
7105
+ idxs: userIndexes,
7073
7106
  constraints,
7074
7107
  schedule
7075
7108
  };