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
package/dist/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;
@@ -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 toSnakeCase(str) {
795
797
  return str.replace(/([A-Z])/g, "_$1").replace(/[-\s]+/g, "_").toLowerCase();
@@ -1631,7 +1633,7 @@ var FromBuilder = class _FromBuilder {
1631
1633
  }
1632
1634
  [QueryBrand] = true;
1633
1635
  where(predicate) {
1634
- const newCondition = predicate(this.table.cols);
1636
+ const newCondition = normalizePredicateExpr(predicate(this.table.cols));
1635
1637
  const nextWhere = this.whereClause ? this.whereClause.and(newCondition) : newCondition;
1636
1638
  return new _FromBuilder(this.table, nextWhere);
1637
1639
  }
@@ -1808,6 +1810,21 @@ function normalizeValue(val) {
1808
1810
  }
1809
1811
  return literal(val);
1810
1812
  }
1813
+ function normalizePredicateExpr(value) {
1814
+ if (value instanceof BooleanExpr) return value;
1815
+ if (typeof value === "boolean") {
1816
+ return new BooleanExpr({
1817
+ type: "eq",
1818
+ left: literal(value),
1819
+ right: literal(true)
1820
+ });
1821
+ }
1822
+ return new BooleanExpr({
1823
+ type: "eq",
1824
+ left: value,
1825
+ right: literal(true)
1826
+ });
1827
+ }
1811
1828
  var BooleanExpr = class _BooleanExpr {
1812
1829
  constructor(data) {
1813
1830
  this.data = data;
@@ -4449,9 +4466,7 @@ var TableCacheImpl = class {
4449
4466
  this.tableDef = tableDef;
4450
4467
  this.rows = /* @__PURE__ */ new Map();
4451
4468
  this.emitter = new EventEmitter();
4452
- const indexesDef = this.tableDef.indexes || [];
4453
- for (const idx of indexesDef) {
4454
- const idxDef = idx;
4469
+ for (const idxDef of this.tableDef.resolvedIndexes) {
4455
4470
  const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
4456
4471
  this[idxDef.name] = index;
4457
4472
  }
@@ -5008,37 +5023,39 @@ async function resolveWS() {
5008
5023
 
5009
5024
  // src/sdk/websocket_decompress_adapter.ts
5010
5025
  var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
5011
- onclose;
5012
- onopen;
5013
- onmessage;
5014
- onerror;
5015
- #ws;
5016
- async #handleOnMessage(msg) {
5017
- const buffer = new Uint8Array(msg.data);
5018
- let decompressed;
5019
- if (buffer[0] === 0) {
5020
- decompressed = buffer.slice(1);
5021
- } else if (buffer[0] === 1) {
5022
- throw new Error(
5023
- "Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
5024
- );
5025
- } else if (buffer[0] === 2) {
5026
- decompressed = await decompress(buffer.slice(1), "gzip");
5027
- } else {
5028
- throw new Error(
5029
- "Unexpected Compression Algorithm. Please use `gzip` or `none`"
5030
- );
5031
- }
5032
- this.onmessage?.({ data: decompressed });
5026
+ set onclose(handler) {
5027
+ this.#ws.onclose = handler;
5033
5028
  }
5034
- #handleOnOpen(msg) {
5035
- this.onopen?.(msg);
5029
+ set onopen(handler) {
5030
+ this.#ws.onopen = handler;
5036
5031
  }
5037
- #handleOnError(msg) {
5038
- this.onerror?.(msg);
5032
+ set onmessage(handler) {
5033
+ this.#ws.onmessage = async (msg) => {
5034
+ const data = await this.#decompress(new Uint8Array(msg.data));
5035
+ handler({ data });
5036
+ };
5039
5037
  }
5040
- #handleOnClose(msg) {
5041
- this.onclose?.(msg);
5038
+ set onerror(handler) {
5039
+ this.#ws.onerror = handler;
5040
+ }
5041
+ #ws;
5042
+ async #decompress(buffer) {
5043
+ const tag = buffer[0];
5044
+ const data = buffer.subarray(1);
5045
+ switch (tag) {
5046
+ case 0:
5047
+ return data;
5048
+ case 1:
5049
+ throw new Error(
5050
+ "Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
5051
+ );
5052
+ case 2:
5053
+ return await decompress(data, "gzip");
5054
+ default:
5055
+ throw new Error(
5056
+ "Unexpected Compression Algorithm. Please use `gzip` or `none`"
5057
+ );
5058
+ }
5042
5059
  }
5043
5060
  send(msg) {
5044
5061
  this.#ws.send(msg);
@@ -5047,14 +5064,6 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
5047
5064
  this.#ws.close();
5048
5065
  }
5049
5066
  constructor(ws) {
5050
- this.onmessage = void 0;
5051
- this.onopen = void 0;
5052
- this.onmessage = void 0;
5053
- this.onerror = void 0;
5054
- ws.onmessage = this.#handleOnMessage.bind(this);
5055
- ws.onerror = this.#handleOnError.bind(this);
5056
- ws.onclose = this.#handleOnClose.bind(this);
5057
- ws.onopen = this.#handleOnOpen.bind(this);
5058
5067
  ws.binaryType = "arraybuffer";
5059
5068
  this.#ws = ws;
5060
5069
  }
@@ -5691,12 +5700,13 @@ var DbConnectionImpl = class {
5691
5700
  }
5692
5701
  #makeReducers(def) {
5693
5702
  const out = {};
5703
+ const writer = new BinaryWriter(1024);
5694
5704
  for (const reducer of def.reducers) {
5695
5705
  const reducerName = reducer.name;
5696
5706
  const key = reducer.accessorName;
5697
5707
  const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
5698
5708
  out[key] = (params) => {
5699
- const writer = new BinaryWriter(1024);
5709
+ writer.clear();
5700
5710
  serializeArgs(writer, params);
5701
5711
  const argsBuffer = writer.getBuffer();
5702
5712
  return this.callReducer(reducerName, argsBuffer, params);
@@ -5706,12 +5716,13 @@ var DbConnectionImpl = class {
5706
5716
  }
5707
5717
  #makeProcedures(def) {
5708
5718
  const out = {};
5719
+ const writer = new BinaryWriter(1024);
5709
5720
  for (const procedure of def.procedures) {
5710
5721
  const procedureName = procedure.name;
5711
5722
  const key = procedure.accessorName;
5712
5723
  const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
5713
5724
  out[key] = (params) => {
5714
- const writer = new BinaryWriter(1024);
5725
+ writer.clear();
5715
5726
  serializeArgs(writer, params);
5716
5727
  const argsBuffer = writer.getBuffer();
5717
5728
  return this.callProcedure(procedureName, argsBuffer).then((returnBuf) => {
@@ -5866,34 +5877,32 @@ var DbConnectionImpl = class {
5866
5877
  }
5867
5878
  return this.#mergeTableUpdates(updates);
5868
5879
  }
5869
- #sendEncoded(wsResolved, message) {
5870
- stdbLogger(
5871
- "trace",
5872
- () => `Sending message to server: ${stringify(message)}`
5873
- );
5874
- const writer = new BinaryWriter(1024);
5875
- ClientMessage.serialize(writer, message);
5876
- const encoded = writer.getBuffer();
5877
- wsResolved.send(encoded);
5878
- }
5879
5880
  #flushOutboundQueue(wsResolved) {
5880
- if (!this.isActive || this.#outboundQueue.length === 0) {
5881
- return;
5882
- }
5883
5881
  const pending = this.#outboundQueue.splice(0);
5884
5882
  for (const message of pending) {
5885
- this.#sendEncoded(wsResolved, message);
5883
+ wsResolved.send(message);
5886
5884
  }
5887
5885
  }
5886
+ #clientMessageEncoder = new BinaryWriter(1024);
5888
5887
  #sendMessage(message) {
5889
- this.wsPromise.then((wsResolved) => {
5890
- if (!wsResolved || !this.isActive) {
5891
- this.#outboundQueue.push(message);
5892
- return;
5893
- }
5894
- this.#flushOutboundQueue(wsResolved);
5895
- this.#sendEncoded(wsResolved, message);
5896
- });
5888
+ const writer = this.#clientMessageEncoder;
5889
+ writer.clear();
5890
+ ClientMessage.serialize(writer, message);
5891
+ const encoded = writer.getBuffer();
5892
+ if (this.ws && this.isActive) {
5893
+ if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
5894
+ stdbLogger(
5895
+ "trace",
5896
+ () => `Sending message to server: ${stringify(message)}`
5897
+ );
5898
+ this.ws.send(encoded);
5899
+ } else {
5900
+ stdbLogger(
5901
+ "trace",
5902
+ () => `Queuing message to server: ${stringify(message)}`
5903
+ );
5904
+ this.#outboundQueue.push(encoded.slice());
5905
+ }
5897
5906
  }
5898
5907
  #nextEventId() {
5899
5908
  this.#eventId += 1;
@@ -6235,11 +6244,7 @@ var DbConnectionImpl = class {
6235
6244
  * ```
6236
6245
  */
6237
6246
  disconnect() {
6238
- this.wsPromise.then((wsResolved) => {
6239
- if (wsResolved) {
6240
- wsResolved.close();
6241
- }
6242
- });
6247
+ this.wsPromise.then((ws) => ws?.close());
6243
6248
  }
6244
6249
  on(eventName, callback) {
6245
6250
  this.#emitter.on(eventName, callback);
@@ -6269,17 +6274,45 @@ var DbConnectionImpl = class {
6269
6274
 
6270
6275
  // src/lib/schema.ts
6271
6276
  function tablesToSchema(ctx, tables) {
6277
+ const tableDefs = /* @__PURE__ */ Object.create(null);
6278
+ for (const [accName, schema2] of Object.entries(tables)) {
6279
+ tableDefs[accName] = tableToSchema(
6280
+ accName,
6281
+ schema2,
6282
+ schema2.tableDef(ctx, accName)
6283
+ );
6284
+ }
6272
6285
  return {
6273
- tables: Object.fromEntries(
6274
- Object.entries(tables).map(([accName, schema2]) => [
6275
- accName,
6276
- tableToSchema(accName, schema2, schema2.tableDef(ctx, accName))
6277
- ])
6278
- )
6286
+ tables: tableDefs
6279
6287
  };
6280
6288
  }
6281
6289
  function tableToSchema(accName, schema2, tableDef) {
6282
6290
  const getColName = (i) => schema2.rowType.algebraicType.value.elements[i].name;
6291
+ const resolvedIndexes = tableDef.indexes.map(
6292
+ (idx) => {
6293
+ const accessorName = idx.accessorName;
6294
+ if (typeof accessorName !== "string" || accessorName.length === 0) {
6295
+ throw new TypeError(
6296
+ `Index '${idx.sourceName ?? "<unknown>"}' on table '${tableDef.sourceName}' is missing accessor name`
6297
+ );
6298
+ }
6299
+ const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
6300
+ const unique = tableDef.constraints.some(
6301
+ (c) => c.data.tag === "Unique" && c.data.value.columns.every((col) => columnIds.includes(col))
6302
+ );
6303
+ const algorithm = {
6304
+ BTree: "btree",
6305
+ Hash: "hash",
6306
+ Direct: "direct"
6307
+ }[idx.algorithm.tag];
6308
+ return {
6309
+ name: accessorName,
6310
+ unique,
6311
+ algorithm,
6312
+ columns: columnIds.map(getColName)
6313
+ };
6314
+ }
6315
+ );
6283
6316
  return {
6284
6317
  // For client,`schama.tableName` will always be there as canonical name.
6285
6318
  // For module, if explicit name is not provided via `name`, accessor name will
@@ -6289,26 +6322,16 @@ function tableToSchema(accName, schema2, tableDef) {
6289
6322
  columns: schema2.rowType.row,
6290
6323
  // typed as T[i]['rowType']['row'] under TablesToSchema<T>
6291
6324
  rowType: schema2.rowSpacetimeType,
6325
+ // Keep declarative indexes in their original shape for type-level consumers.
6326
+ indexes: schema2.idxs,
6292
6327
  constraints: tableDef.constraints.map((c) => ({
6293
6328
  name: c.sourceName,
6294
6329
  constraint: "unique",
6295
6330
  columns: c.data.value.columns.map(getColName)
6296
6331
  })),
6297
- // TODO: horrible horrible horrible. we smuggle this `Array<UntypedIndex>`
6298
- // by casting it to an `Array<IndexOpts>` as `TableToSchema` expects.
6299
- // This is then used in `TableCacheImpl.constructor` and who knows where else.
6300
- // We should stop lying about our types.
6301
- indexes: tableDef.indexes.map((idx) => {
6302
- const columnIds = idx.algorithm.tag === "Direct" ? [idx.algorithm.value] : idx.algorithm.value;
6303
- return {
6304
- name: idx.accessorName,
6305
- unique: tableDef.constraints.some(
6306
- (c) => c.data.value.columns.every((col) => columnIds.includes(col))
6307
- ),
6308
- algorithm: idx.algorithm.tag.toLowerCase(),
6309
- columns: columnIds.map(getColName)
6310
- };
6311
- }),
6332
+ // Expose resolved runtime indexes separately so runtime users don't have to
6333
+ // reinterpret `indexes` with unsafe casts.
6334
+ resolvedIndexes,
6312
6335
  tableDef,
6313
6336
  ...tableDef.isEvent ? { isEvent: true } : {}
6314
6337
  };
@@ -7132,6 +7155,14 @@ function table(opts, row, ..._) {
7132
7155
  }
7133
7156
  }
7134
7157
  for (const indexOpts of userIndexes ?? []) {
7158
+ const accessor = indexOpts.accessor;
7159
+ if (typeof accessor !== "string" || accessor.length === 0) {
7160
+ const tableLabel = name ?? "<unnamed>";
7161
+ const indexLabel = indexOpts.name ?? "<unnamed>";
7162
+ throw new TypeError(
7163
+ `Index '${indexLabel}' on table '${tableLabel}' must define a non-empty 'accessor'`
7164
+ );
7165
+ }
7135
7166
  let algorithm;
7136
7167
  switch (indexOpts.algorithm) {
7137
7168
  case "btree":
@@ -7152,7 +7183,7 @@ function table(opts, row, ..._) {
7152
7183
  }
7153
7184
  indexes.push({
7154
7185
  sourceName: void 0,
7155
- accessorName: indexOpts.accessor,
7186
+ accessorName: accessor,
7156
7187
  algorithm,
7157
7188
  canonicalName: indexOpts.name
7158
7189
  });
@@ -7202,7 +7233,9 @@ function table(opts, row, ..._) {
7202
7233
  isEvent
7203
7234
  };
7204
7235
  },
7205
- idxs: {},
7236
+ // Preserve the declared index options as runtime data so `tableToSchema`
7237
+ // can expose them without type-smuggling.
7238
+ idxs: userIndexes,
7206
7239
  constraints,
7207
7240
  schedule
7208
7241
  };