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