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