spacetimedb 2.0.4 → 2.2.0

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 (116) hide show
  1. package/LICENSE.txt +2 -2
  2. package/dist/angular/index.cjs +9 -3
  3. package/dist/angular/index.cjs.map +1 -1
  4. package/dist/angular/index.mjs +9 -3
  5. package/dist/angular/index.mjs.map +1 -1
  6. package/dist/browser/angular/index.mjs +9 -3
  7. package/dist/browser/angular/index.mjs.map +1 -1
  8. package/dist/browser/react/index.mjs +62 -7
  9. package/dist/browser/react/index.mjs.map +1 -1
  10. package/dist/browser/svelte/index.mjs +9 -3
  11. package/dist/browser/svelte/index.mjs.map +1 -1
  12. package/dist/browser/vue/index.mjs +9 -3
  13. package/dist/browser/vue/index.mjs.map +1 -1
  14. package/dist/index.browser.mjs +481 -146
  15. package/dist/index.browser.mjs.map +1 -1
  16. package/dist/index.cjs +481 -146
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +481 -146
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/lib/algebraic_type.d.ts.map +1 -1
  21. package/dist/lib/binary_reader.d.ts +1 -1
  22. package/dist/lib/binary_reader.d.ts.map +1 -1
  23. package/dist/lib/binary_writer.d.ts +2 -1
  24. package/dist/lib/binary_writer.d.ts.map +1 -1
  25. package/dist/lib/filter.d.ts +2 -1
  26. package/dist/lib/filter.d.ts.map +1 -1
  27. package/dist/lib/query.d.ts +10 -5
  28. package/dist/lib/query.d.ts.map +1 -1
  29. package/dist/lib/table.d.ts +12 -1
  30. package/dist/lib/table.d.ts.map +1 -1
  31. package/dist/min/index.browser.mjs +1 -1
  32. package/dist/min/index.browser.mjs.map +1 -1
  33. package/dist/min/react/index.mjs +1 -1
  34. package/dist/min/react/index.mjs.map +1 -1
  35. package/dist/min/sdk/index.browser.mjs +1 -1
  36. package/dist/min/sdk/index.browser.mjs.map +1 -1
  37. package/dist/react/index.cjs +62 -6
  38. package/dist/react/index.cjs.map +1 -1
  39. package/dist/react/index.d.ts +1 -0
  40. package/dist/react/index.d.ts.map +1 -1
  41. package/dist/react/index.mjs +62 -7
  42. package/dist/react/index.mjs.map +1 -1
  43. package/dist/react/useProcedure.d.ts +4 -0
  44. package/dist/react/useProcedure.d.ts.map +1 -0
  45. package/dist/react/useTable.d.ts +2 -0
  46. package/dist/react/useTable.d.ts.map +1 -1
  47. package/dist/sdk/db_connection_builder.d.ts +3 -3
  48. package/dist/sdk/db_connection_builder.d.ts.map +1 -1
  49. package/dist/sdk/db_connection_impl.d.ts +3 -3
  50. package/dist/sdk/db_connection_impl.d.ts.map +1 -1
  51. package/dist/sdk/decompress.d.ts +1 -1
  52. package/dist/sdk/decompress.d.ts.map +1 -1
  53. package/dist/sdk/index.browser.mjs +477 -144
  54. package/dist/sdk/index.browser.mjs.map +1 -1
  55. package/dist/sdk/index.cjs +477 -144
  56. package/dist/sdk/index.cjs.map +1 -1
  57. package/dist/sdk/index.mjs +477 -144
  58. package/dist/sdk/index.mjs.map +1 -1
  59. package/dist/sdk/table_cache.d.ts +1 -0
  60. package/dist/sdk/table_cache.d.ts.map +1 -1
  61. package/dist/sdk/type_utils.d.ts +4 -1
  62. package/dist/sdk/type_utils.d.ts.map +1 -1
  63. package/dist/sdk/websocket_decompress_adapter.d.ts +5 -21
  64. package/dist/sdk/websocket_decompress_adapter.d.ts.map +1 -1
  65. package/dist/sdk/websocket_protocols.d.ts +6 -0
  66. package/dist/sdk/websocket_protocols.d.ts.map +1 -0
  67. package/dist/sdk/websocket_test_adapter.d.ts +14 -18
  68. package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
  69. package/dist/sdk/websocket_v3_frames.d.ts +9 -0
  70. package/dist/sdk/websocket_v3_frames.d.ts.map +1 -0
  71. package/dist/sdk/ws.d.ts +26 -1
  72. package/dist/sdk/ws.d.ts.map +1 -1
  73. package/dist/server/http_internal.d.ts.map +1 -1
  74. package/dist/server/index.d.ts +2 -1
  75. package/dist/server/index.d.ts.map +1 -1
  76. package/dist/server/index.mjs +76 -15
  77. package/dist/server/index.mjs.map +1 -1
  78. package/dist/server/runtime.d.ts +29 -2
  79. package/dist/server/runtime.d.ts.map +1 -1
  80. package/dist/svelte/index.cjs +9 -3
  81. package/dist/svelte/index.cjs.map +1 -1
  82. package/dist/svelte/index.mjs +9 -3
  83. package/dist/svelte/index.mjs.map +1 -1
  84. package/dist/tanstack/index.cjs +9 -3
  85. package/dist/tanstack/index.cjs.map +1 -1
  86. package/dist/tanstack/index.mjs +9 -3
  87. package/dist/tanstack/index.mjs.map +1 -1
  88. package/dist/vue/index.cjs +9 -3
  89. package/dist/vue/index.cjs.map +1 -1
  90. package/dist/vue/index.mjs +9 -3
  91. package/dist/vue/index.mjs.map +1 -1
  92. package/package.json +2 -2
  93. package/src/lib/algebraic_type.ts +5 -1
  94. package/src/lib/binary_reader.ts +5 -2
  95. package/src/lib/binary_writer.ts +7 -1
  96. package/src/lib/filter.ts +12 -1
  97. package/src/lib/query.ts +60 -19
  98. package/src/lib/table.ts +15 -2
  99. package/src/react/index.ts +1 -0
  100. package/src/react/useProcedure.ts +60 -0
  101. package/src/react/useTable.ts +22 -2
  102. package/src/sdk/db_connection_builder.ts +16 -7
  103. package/src/sdk/db_connection_impl.ts +404 -89
  104. package/src/sdk/decompress.ts +7 -23
  105. package/src/sdk/table_cache.ts +5 -5
  106. package/src/sdk/type_utils.ts +10 -1
  107. package/src/sdk/websocket_decompress_adapter.ts +15 -77
  108. package/src/sdk/websocket_protocols.ts +25 -0
  109. package/src/sdk/websocket_test_adapter.ts +65 -29
  110. package/src/sdk/websocket_v3_frames.ts +126 -0
  111. package/src/sdk/ws.ts +81 -3
  112. package/src/server/http_internal.ts +10 -1
  113. package/src/server/index.ts +2 -1
  114. package/src/server/runtime.ts +39 -1
  115. package/src/server/sys.d.ts +4 -0
  116. package/src/server/view.test-d.ts +4 -0
package/dist/index.mjs CHANGED
@@ -428,8 +428,8 @@ var BinaryReader = class {
428
428
  this.view = input instanceof DataView ? input : new DataView(input.buffer, input.byteOffset, input.byteLength);
429
429
  this.offset = 0;
430
430
  }
431
- reset(view) {
432
- this.view = view;
431
+ reset(input) {
432
+ this.view = input instanceof DataView ? input : new DataView(input.buffer, input.byteOffset, input.byteLength);
433
433
  this.offset = 0;
434
434
  }
435
435
  get remaining() {
@@ -621,6 +621,11 @@ var BinaryWriter = class {
621
621
  this.view.setUint8(this.offset, value);
622
622
  this.offset += 1;
623
623
  }
624
+ writeBytes(value) {
625
+ this.expandBuffer(value.length);
626
+ new Uint8Array(this.buffer.buffer, this.offset, value.length).set(value);
627
+ this.offset += value.length;
628
+ }
624
629
  writeI8(value) {
625
630
  this.expandBuffer(1);
626
631
  this.view.setInt8(this.offset, value);
@@ -1223,7 +1228,8 @@ writer.offset += ${primitiveSizes[tag]};` : `writer.write${tag}(value.${name});`
1223
1228
  const result = { ${ty.elements.map(getElementInitializer).join(", ")} };
1224
1229
  const view = reader.view;
1225
1230
  ${ty.elements.map(
1226
- ({ name, algebraicType: { tag } }) => tag in primitiveJSName ? `result.${name} = view.get${primitiveJSName[tag]}(reader.offset, ${primitiveSizes[tag] > 1 ? "true" : ""});
1231
+ ({ name, algebraicType: { tag } }) => tag in primitiveJSName ? tag === "Bool" ? `result.${name} = view.getUint8(reader.offset) !== 0;
1232
+ reader.offset += 1;` : `result.${name} = view.get${primitiveJSName[tag]}(reader.offset, ${primitiveSizes[tag] > 1 ? "true" : ""});
1227
1233
  reader.offset += ${primitiveSizes[tag]};` : `result.${name} = reader.read${tag}();`
1228
1234
  ).join("\n")}
1229
1235
  return result;`;
@@ -1726,7 +1732,8 @@ function createRowExpr(tableDef) {
1726
1732
  const column = new ColumnExpression(
1727
1733
  tableDef.sourceName,
1728
1734
  columnName,
1729
- columnBuilder.typeBuilder.algebraicType
1735
+ columnBuilder.typeBuilder.algebraicType,
1736
+ columnBuilder.columnMetadata.name
1730
1737
  );
1731
1738
  row[columnName] = Object.freeze(column);
1732
1739
  }
@@ -1744,14 +1751,18 @@ function renderSelectSqlWithJoins(table2, where, extraClauses = []) {
1744
1751
  }
1745
1752
  var ColumnExpression = class {
1746
1753
  type = "column";
1754
+ // This is the column accessor
1747
1755
  column;
1756
+ // The name of the column in the database.
1757
+ columnName;
1748
1758
  table;
1749
1759
  // phantom: actual runtime value is undefined
1750
1760
  tsValueType;
1751
1761
  spacetimeType;
1752
- constructor(table2, column, spacetimeType) {
1762
+ constructor(table2, column, spacetimeType, columnName) {
1753
1763
  this.table = table2;
1754
1764
  this.column = column;
1765
+ this.columnName = columnName || column;
1755
1766
  this.spacetimeType = spacetimeType;
1756
1767
  }
1757
1768
  eq(x) {
@@ -1828,10 +1839,16 @@ var BooleanExpr = class _BooleanExpr {
1828
1839
  this.data = data;
1829
1840
  }
1830
1841
  and(other) {
1831
- return new _BooleanExpr({ type: "and", clauses: [this.data, other.data] });
1842
+ return new _BooleanExpr({
1843
+ type: "and",
1844
+ clauses: [this.data, other.data]
1845
+ });
1832
1846
  }
1833
1847
  or(other) {
1834
- return new _BooleanExpr({ type: "or", clauses: [this.data, other.data] });
1848
+ return new _BooleanExpr({
1849
+ type: "or",
1850
+ clauses: [this.data, other.data]
1851
+ });
1835
1852
  }
1836
1853
  not() {
1837
1854
  return new _BooleanExpr({ type: "not", clause: this.data });
@@ -1840,13 +1857,15 @@ var BooleanExpr = class _BooleanExpr {
1840
1857
  function not(clause) {
1841
1858
  return new BooleanExpr({ type: "not", clause: clause.data });
1842
1859
  }
1843
- function and(...clauses) {
1860
+ function and(first, second, ...rest) {
1861
+ const clauses = [first, second, ...rest];
1844
1862
  return new BooleanExpr({
1845
1863
  type: "and",
1846
1864
  clauses: clauses.map((c) => c.data)
1847
1865
  });
1848
1866
  }
1849
- function or(...clauses) {
1867
+ function or(first, second, ...rest) {
1868
+ const clauses = [first, second, ...rest];
1850
1869
  return new BooleanExpr({
1851
1870
  type: "or",
1852
1871
  clauses: clauses.map((c) => c.data)
@@ -1883,7 +1902,7 @@ function valueExprToSql(expr, tableAlias) {
1883
1902
  return literalValueToSql(expr.value);
1884
1903
  }
1885
1904
  const table2 = expr.table;
1886
- return `${quoteIdentifier(table2)}.${quoteIdentifier(expr.column)}`;
1905
+ return `${quoteIdentifier(table2)}.${quoteIdentifier(expr.columnName)}`;
1887
1906
  }
1888
1907
  function literalValueToSql(value) {
1889
1908
  if (value === null || value === void 0) {
@@ -4451,6 +4470,7 @@ var scalarCompare = (x, y) => {
4451
4470
  return x < y ? -1 : 1;
4452
4471
  };
4453
4472
  var TableCacheImpl = class {
4473
+ hasPrimaryKey;
4454
4474
  rows;
4455
4475
  tableDef;
4456
4476
  emitter;
@@ -4464,6 +4484,9 @@ var TableCacheImpl = class {
4464
4484
  this.tableDef = tableDef;
4465
4485
  this.rows = /* @__PURE__ */ new Map();
4466
4486
  this.emitter = new EventEmitter();
4487
+ this.hasPrimaryKey = Object.values(this.tableDef.columns).some(
4488
+ (col) => col.columnMetadata.isPrimaryKey === true
4489
+ );
4467
4490
  for (const idxDef of this.tableDef.resolvedIndexes) {
4468
4491
  const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
4469
4492
  this[idxDef.name] = index;
@@ -4573,10 +4596,7 @@ var TableCacheImpl = class {
4573
4596
  }
4574
4597
  return pendingCallbacks;
4575
4598
  }
4576
- const hasPrimaryKey = Object.values(this.tableDef.columns).some(
4577
- (col) => col.columnMetadata.isPrimaryKey === true
4578
- );
4579
- if (hasPrimaryKey) {
4599
+ if (this.hasPrimaryKey) {
4580
4600
  const insertMap = /* @__PURE__ */ new Map();
4581
4601
  const deleteMap = /* @__PURE__ */ new Map();
4582
4602
  for (const op of operations) {
@@ -4984,27 +5004,17 @@ async function decompress(buffer, type, chunkSize = 128 * 1024) {
4984
5004
  });
4985
5005
  const decompressionStream = new DecompressionStream(type);
4986
5006
  const decompressedStream = readableStream.pipeThrough(decompressionStream);
4987
- const reader = decompressedStream.getReader();
4988
5007
  const chunks = [];
4989
- let totalLength = 0;
4990
- let result;
4991
- while (!(result = await reader.read()).done) {
4992
- chunks.push(result.value);
4993
- totalLength += result.value.length;
4994
- }
4995
- const decompressedArray = new Uint8Array(totalLength);
4996
- let chunkOffset = 0;
4997
- for (const chunk of chunks) {
4998
- decompressedArray.set(chunk, chunkOffset);
4999
- chunkOffset += chunk.length;
5000
- }
5001
- return decompressedArray;
5008
+ for await (const chunk of decompressedStream) {
5009
+ chunks.push(chunk);
5010
+ }
5011
+ return new Blob(chunks).bytes();
5002
5012
  }
5003
5013
 
5004
5014
  // src/sdk/ws.ts
5005
5015
  async function resolveWS() {
5006
- if (typeof globalThis.WebSocket !== "undefined") {
5007
- return globalThis.WebSocket;
5016
+ if (typeof WebSocket !== "undefined") {
5017
+ return WebSocket;
5008
5018
  }
5009
5019
  const dynamicImport = new Function("m", "return import(m)");
5010
5020
  try {
@@ -5018,9 +5028,54 @@ async function resolveWS() {
5018
5028
  throw err;
5019
5029
  }
5020
5030
  }
5031
+ async function openWebSocket({
5032
+ url,
5033
+ nameOrAddress,
5034
+ wsProtocol,
5035
+ authToken,
5036
+ compression,
5037
+ lightMode,
5038
+ confirmedReads
5039
+ }) {
5040
+ const headers = new Headers();
5041
+ const WS = await resolveWS();
5042
+ let temporaryAuthToken;
5043
+ if (authToken) {
5044
+ headers.set("Authorization", `Bearer ${authToken}`);
5045
+ const tokenUrl = new URL("v1/identity/websocket-token", url);
5046
+ tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
5047
+ const response = await fetch(tokenUrl, { method: "POST", headers });
5048
+ if (response.ok) {
5049
+ const { token } = await response.json();
5050
+ temporaryAuthToken = token;
5051
+ } else {
5052
+ throw new Error(`Failed to verify token: ${response.statusText}`);
5053
+ }
5054
+ }
5055
+ const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
5056
+ if (temporaryAuthToken) {
5057
+ databaseUrl.searchParams.set("token", temporaryAuthToken);
5058
+ }
5059
+ databaseUrl.searchParams.set(
5060
+ "compression",
5061
+ { gzip: "Gzip", brotli: "Brotli", none: "None" }[compression] ?? "None"
5062
+ );
5063
+ if (lightMode) {
5064
+ databaseUrl.searchParams.set("light", "true");
5065
+ }
5066
+ if (confirmedReads !== void 0) {
5067
+ databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
5068
+ }
5069
+ const ws = new WS(databaseUrl.toString(), wsProtocol);
5070
+ ws.binaryType = "arraybuffer";
5071
+ return ws;
5072
+ }
5021
5073
 
5022
5074
  // src/sdk/websocket_decompress_adapter.ts
5023
5075
  var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
5076
+ get protocol() {
5077
+ return this.#ws.protocol;
5078
+ }
5024
5079
  set onclose(handler) {
5025
5080
  this.#ws.onclose = handler;
5026
5081
  }
@@ -5044,9 +5099,7 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
5044
5099
  case 0:
5045
5100
  return data;
5046
5101
  case 1:
5047
- throw new Error(
5048
- "Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
5049
- );
5102
+ return await decompress(data, "brotli");
5050
5103
  case 2:
5051
5104
  return await decompress(data, "gzip");
5052
5105
  default:
@@ -5062,51 +5115,10 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
5062
5115
  this.#ws.close();
5063
5116
  }
5064
5117
  constructor(ws) {
5065
- ws.binaryType = "arraybuffer";
5066
5118
  this.#ws = ws;
5067
5119
  }
5068
- static async createWebSocketFn({
5069
- url,
5070
- nameOrAddress,
5071
- wsProtocol,
5072
- authToken,
5073
- compression,
5074
- lightMode,
5075
- confirmedReads
5076
- }) {
5077
- const headers = new Headers();
5078
- const WS = await resolveWS();
5079
- let temporaryAuthToken = void 0;
5080
- if (authToken) {
5081
- headers.set("Authorization", `Bearer ${authToken}`);
5082
- const tokenUrl = new URL("v1/identity/websocket-token", url);
5083
- tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
5084
- const response = await fetch(tokenUrl, { method: "POST", headers });
5085
- if (response.ok) {
5086
- const { token } = await response.json();
5087
- temporaryAuthToken = token;
5088
- } else {
5089
- return Promise.reject(
5090
- new Error(`Failed to verify token: ${response.statusText}`)
5091
- );
5092
- }
5093
- }
5094
- const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
5095
- if (temporaryAuthToken) {
5096
- databaseUrl.searchParams.set("token", temporaryAuthToken);
5097
- }
5098
- databaseUrl.searchParams.set(
5099
- "compression",
5100
- compression === "gzip" ? "Gzip" : "None"
5101
- );
5102
- if (lightMode) {
5103
- databaseUrl.searchParams.set("light", "true");
5104
- }
5105
- if (confirmedReads !== void 0) {
5106
- databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
5107
- }
5108
- const ws = new WS(databaseUrl.toString(), wsProtocol);
5109
- return new _WebsocketDecompressAdapter(ws);
5120
+ static async openWebSocket(args) {
5121
+ return new _WebsocketDecompressAdapter(await openWebSocket(args));
5110
5122
  }
5111
5123
  };
5112
5124
 
@@ -5123,7 +5135,7 @@ var DbConnectionBuilder = class {
5123
5135
  constructor(remoteModule, dbConnectionCtor) {
5124
5136
  this.remoteModule = remoteModule;
5125
5137
  this.dbConnectionCtor = dbConnectionCtor;
5126
- this.#createWSFn = WebsocketDecompressAdapter.createWebSocketFn;
5138
+ this.#createWSFn = WebsocketDecompressAdapter.openWebSocket;
5127
5139
  }
5128
5140
  #uri;
5129
5141
  #nameOrAddress;
@@ -5178,6 +5190,16 @@ var DbConnectionBuilder = class {
5178
5190
  * @param compression The compression algorithm to use for the connection.
5179
5191
  */
5180
5192
  withCompression(compression) {
5193
+ if (compression === "brotli") {
5194
+ try {
5195
+ new DecompressionStream("brotli");
5196
+ } catch (e) {
5197
+ throw new TypeError(
5198
+ `Brotli compression is not supported by the runtime. Please choose a different compression method.`,
5199
+ { cause: e }
5200
+ );
5201
+ }
5202
+ }
5181
5203
  this.#compression = compression;
5182
5204
  return this;
5183
5205
  }
@@ -5541,6 +5563,100 @@ var SubscriptionHandleImpl = class {
5541
5563
  return this.#activeState;
5542
5564
  }
5543
5565
  };
5566
+
5567
+ // src/sdk/websocket_protocols.ts
5568
+ var V2_WS_PROTOCOL = "v2.bsatn.spacetimedb";
5569
+ var V3_WS_PROTOCOL = "v3.bsatn.spacetimedb";
5570
+ var PREFERRED_WS_PROTOCOLS = [V3_WS_PROTOCOL, V2_WS_PROTOCOL];
5571
+ function normalizeWsProtocol(protocol) {
5572
+ if (protocol === V3_WS_PROTOCOL) {
5573
+ return V3_WS_PROTOCOL;
5574
+ }
5575
+ if (protocol === "" || protocol === V2_WS_PROTOCOL) {
5576
+ return V2_WS_PROTOCOL;
5577
+ }
5578
+ stdbLogger(
5579
+ "warn",
5580
+ `Unexpected websocket subprotocol "${protocol}", falling back to ${V2_WS_PROTOCOL}.`
5581
+ );
5582
+ return V2_WS_PROTOCOL;
5583
+ }
5584
+
5585
+ // src/sdk/websocket_v3_frames.ts
5586
+ var EMPTY_V3_PAYLOAD_ERR = "v3 websocket payloads must contain at least one message";
5587
+ function ensureMessages(messages) {
5588
+ if (messages.length === 0) {
5589
+ throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
5590
+ }
5591
+ }
5592
+ function ensureMessageCount(messages, messageCount) {
5593
+ ensureMessages(messages);
5594
+ if (messageCount < 1 || messageCount > messages.length) {
5595
+ throw new RangeError(
5596
+ `v3 websocket payload requested ${messageCount} messages from ${messages.length}`
5597
+ );
5598
+ }
5599
+ }
5600
+ function concatenateMessagesV3(writer, messages, messageCount = messages.length) {
5601
+ ensureMessageCount(messages, messageCount);
5602
+ writer.clear();
5603
+ for (let i = 0; i < messageCount; i++) {
5604
+ writer.writeBytes(messages[i]);
5605
+ }
5606
+ return writer.getBuffer();
5607
+ }
5608
+ function countClientMessagesForV3Frame(messages, maxFrameBytes) {
5609
+ ensureMessages(messages);
5610
+ const firstMessage = messages[0];
5611
+ if (firstMessage.length > maxFrameBytes) {
5612
+ return 1;
5613
+ }
5614
+ let count = 1;
5615
+ let frameSize = firstMessage.length;
5616
+ while (count < messages.length) {
5617
+ const nextMessage = messages[count];
5618
+ const nextFrameSize = frameSize + nextMessage.length;
5619
+ if (nextFrameSize > maxFrameBytes) {
5620
+ break;
5621
+ }
5622
+ frameSize = nextFrameSize;
5623
+ count += 1;
5624
+ }
5625
+ return count;
5626
+ }
5627
+ function encodeClientMessagesV3(writer, messages, messageCount = messages.length) {
5628
+ return concatenateMessagesV3(writer, messages, messageCount);
5629
+ }
5630
+ function forEachServerMessageV3(reader, data, visit) {
5631
+ reader.reset(data);
5632
+ if (reader.remaining === 0) {
5633
+ throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
5634
+ }
5635
+ let count = 0;
5636
+ while (reader.remaining > 0) {
5637
+ visit(ServerMessage.deserialize(reader));
5638
+ count += 1;
5639
+ }
5640
+ return count;
5641
+ }
5642
+
5643
+ // src/sdk/db_connection_impl.ts
5644
+ var TEXT_ENCODER = new TextEncoder();
5645
+ function getClientMessageVariantTag(name) {
5646
+ if (ClientMessage.algebraicType.tag !== "Sum") {
5647
+ throw new TypeError("ClientMessage must be a sum type");
5648
+ }
5649
+ const tag = ClientMessage.algebraicType.value.variants.findIndex(
5650
+ (variant) => variant.name === name
5651
+ );
5652
+ if (tag === -1) {
5653
+ throw new RangeError(`Unknown ClientMessage variant: ${name}`);
5654
+ }
5655
+ return tag;
5656
+ }
5657
+ var CLIENT_MESSAGE_CALL_REDUCER_TAG = getClientMessageVariantTag("CallReducer");
5658
+ var CLIENT_MESSAGE_CALL_PROCEDURE_TAG = getClientMessageVariantTag("CallProcedure");
5659
+ var MAX_V3_OUTBOUND_FRAME_BYTES = 256 * 1024;
5544
5660
  var DbConnectionImpl = class {
5545
5661
  /**
5546
5662
  * Whether or not the connection is active.
@@ -5575,22 +5691,35 @@ var DbConnectionImpl = class {
5575
5691
  * The `ConnectionId` of the connection to to the database.
5576
5692
  */
5577
5693
  connectionId = ConnectionId.random();
5694
+ #connectionIdHex = this.connectionId.toHexString();
5578
5695
  // These fields are meant to be strictly private.
5579
5696
  #queryId = 0;
5580
5697
  #requestId = 0;
5581
5698
  #eventId = 0;
5582
5699
  #emitter;
5583
- #messageQueue = Promise.resolve();
5700
+ #inboundQueue = [];
5701
+ #inboundQueueOffset = 0;
5702
+ #isDrainingInboundQueue = false;
5584
5703
  #outboundQueue = [];
5704
+ #isOutboundFlushScheduled = false;
5705
+ #negotiatedWsProtocol = V2_WS_PROTOCOL;
5585
5706
  #subscriptionManager = new SubscriptionManager();
5586
5707
  #remoteModule;
5587
5708
  #reducerCallbacks = /* @__PURE__ */ new Map();
5588
5709
  #reducerCallInfo = /* @__PURE__ */ new Map();
5589
5710
  #procedureCallbacks = /* @__PURE__ */ new Map();
5590
5711
  #rowDeserializers;
5712
+ #rowIdMetadata;
5591
5713
  #reducerArgsSerializers;
5592
5714
  #procedureSerializers;
5715
+ #reducerNameBytes;
5716
+ #procedureNameBytes;
5593
5717
  #sourceNameToTableDef;
5718
+ #messageReader = new BinaryReader(new Uint8Array());
5719
+ #rowListReader = new BinaryReader(new Uint8Array());
5720
+ #clientFrameEncoder = new BinaryWriter(1024);
5721
+ #boundSubscriptionBuilder;
5722
+ #boundDisconnect;
5594
5723
  // These fields are not part of the public API, but in a pinch you
5595
5724
  // could use JavaScript to access them by bypassing TypeScript's
5596
5725
  // private fields.
@@ -5619,22 +5748,35 @@ var DbConnectionImpl = class {
5619
5748
  this.token = token;
5620
5749
  this.#remoteModule = remoteModule;
5621
5750
  this.#emitter = emitter;
5751
+ this.#boundSubscriptionBuilder = this.subscriptionBuilder.bind(this);
5752
+ this.#boundDisconnect = this.disconnect.bind(this);
5622
5753
  this.#rowDeserializers = /* @__PURE__ */ Object.create(null);
5754
+ this.#rowIdMetadata = /* @__PURE__ */ Object.create(null);
5623
5755
  this.#sourceNameToTableDef = /* @__PURE__ */ Object.create(null);
5624
5756
  for (const table2 of Object.values(remoteModule.tables)) {
5625
5757
  this.#rowDeserializers[table2.sourceName] = ProductType.makeDeserializer(
5626
5758
  table2.rowType
5627
5759
  );
5628
5760
  this.#sourceNameToTableDef[table2.sourceName] = table2;
5761
+ const primaryKeyColumn = Object.entries(table2.columns).find(
5762
+ ([, column]) => column.columnMetadata.isPrimaryKey
5763
+ );
5764
+ this.#rowIdMetadata[table2.sourceName] = primaryKeyColumn ? {
5765
+ primaryKeyColName: primaryKeyColumn[0],
5766
+ primaryKeyColType: primaryKeyColumn[1].typeBuilder.algebraicType
5767
+ } : {};
5629
5768
  }
5630
5769
  this.#reducerArgsSerializers = /* @__PURE__ */ Object.create(null);
5770
+ this.#reducerNameBytes = /* @__PURE__ */ Object.create(null);
5631
5771
  for (const reducer of remoteModule.reducers) {
5632
5772
  this.#reducerArgsSerializers[reducer.name] = {
5633
5773
  serialize: ProductType.makeSerializer(reducer.paramsType),
5634
5774
  deserialize: ProductType.makeDeserializer(reducer.paramsType)
5635
5775
  };
5776
+ this.#reducerNameBytes[reducer.name] = TEXT_ENCODER.encode(reducer.name);
5636
5777
  }
5637
5778
  this.#procedureSerializers = /* @__PURE__ */ Object.create(null);
5779
+ this.#procedureNameBytes = /* @__PURE__ */ Object.create(null);
5638
5780
  for (const procedure of remoteModule.procedures) {
5639
5781
  this.#procedureSerializers[procedure.name] = {
5640
5782
  serializeArgs: ProductType.makeSerializer(
@@ -5644,9 +5786,11 @@ var DbConnectionImpl = class {
5644
5786
  procedure.returnType.algebraicType
5645
5787
  )
5646
5788
  };
5789
+ this.#procedureNameBytes[procedure.name] = TEXT_ENCODER.encode(
5790
+ procedure.name
5791
+ );
5647
5792
  }
5648
- const connectionId = this.connectionId.toHexString();
5649
- url.searchParams.set("connection_id", connectionId);
5793
+ url.searchParams.set("connection_id", this.#connectionIdHex);
5650
5794
  this.clientCache = new ClientCache();
5651
5795
  this.db = this.#makeDbView();
5652
5796
  this.reducers = this.#makeReducers(remoteModule);
@@ -5654,7 +5798,7 @@ var DbConnectionImpl = class {
5654
5798
  this.wsPromise = createWSFn({
5655
5799
  url,
5656
5800
  nameOrAddress,
5657
- wsProtocol: "v2.bsatn.spacetimedb",
5801
+ wsProtocol: [...PREFERRED_WS_PROTOCOLS],
5658
5802
  authToken: token,
5659
5803
  compression,
5660
5804
  lightMode,
@@ -5698,16 +5842,22 @@ var DbConnectionImpl = class {
5698
5842
  }
5699
5843
  #makeReducers(def) {
5700
5844
  const out = {};
5701
- const writer = new BinaryWriter(1024);
5702
5845
  for (const reducer of def.reducers) {
5703
5846
  const reducerName = reducer.name;
5847
+ const encodedReducerName = this.#reducerNameBytes[reducerName];
5704
5848
  const key = reducer.accessorName;
5705
5849
  const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
5706
5850
  out[key] = (params) => {
5851
+ const writer = this.#reducerArgsEncoder;
5707
5852
  writer.clear();
5708
5853
  serializeArgs(writer, params);
5709
5854
  const argsBuffer = writer.getBuffer();
5710
- return this.callReducer(reducerName, argsBuffer, params);
5855
+ return this.#callReducerWithEncodedName(
5856
+ reducerName,
5857
+ encodedReducerName,
5858
+ argsBuffer,
5859
+ params
5860
+ );
5711
5861
  };
5712
5862
  }
5713
5863
  return out;
@@ -5717,13 +5867,18 @@ var DbConnectionImpl = class {
5717
5867
  const writer = new BinaryWriter(1024);
5718
5868
  for (const procedure of def.procedures) {
5719
5869
  const procedureName = procedure.name;
5870
+ const encodedProcedureName = this.#procedureNameBytes[procedureName];
5720
5871
  const key = procedure.accessorName;
5721
5872
  const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
5722
5873
  out[key] = (params) => {
5723
5874
  writer.clear();
5724
5875
  serializeArgs(writer, params);
5725
5876
  const argsBuffer = writer.getBuffer();
5726
- return this.callProcedure(procedureName, argsBuffer).then((returnBuf) => {
5877
+ return this.#callProcedureWithEncodedName(
5878
+ procedureName,
5879
+ encodedProcedureName,
5880
+ argsBuffer
5881
+ ).then((returnBuf) => {
5727
5882
  return deserializeReturn(new BinaryReader(returnBuf));
5728
5883
  });
5729
5884
  };
@@ -5735,8 +5890,8 @@ var DbConnectionImpl = class {
5735
5890
  db: this.db,
5736
5891
  reducers: this.reducers,
5737
5892
  isActive: this.isActive,
5738
- subscriptionBuilder: this.subscriptionBuilder.bind(this),
5739
- disconnect: this.disconnect.bind(this),
5893
+ subscriptionBuilder: this.#boundSubscriptionBuilder,
5894
+ disconnect: this.#boundDisconnect,
5740
5895
  event
5741
5896
  };
5742
5897
  }
@@ -5781,21 +5936,16 @@ var DbConnectionImpl = class {
5781
5936
  }
5782
5937
  #parseRowList(type, tableName, rowList) {
5783
5938
  const buffer = rowList.rowsData;
5784
- const reader = new BinaryReader(buffer);
5939
+ const reader = this.#rowListReader;
5940
+ reader.reset(buffer);
5785
5941
  const rows = [];
5786
5942
  const deserializeRow = this.#rowDeserializers[tableName];
5787
- const table2 = this.#sourceNameToTableDef[tableName];
5788
- const columnsArray = Object.entries(table2.columns);
5789
- const primaryKeyColumnEntry = columnsArray.find(
5790
- (col) => col[1].columnMetadata.isPrimaryKey
5791
- );
5943
+ const { primaryKeyColName, primaryKeyColType } = this.#rowIdMetadata[tableName];
5792
5944
  let previousOffset = 0;
5793
5945
  while (reader.remaining > 0) {
5794
5946
  const row = deserializeRow(reader);
5795
5947
  let rowId = void 0;
5796
- if (primaryKeyColumnEntry !== void 0) {
5797
- const primaryKeyColName = primaryKeyColumnEntry[0];
5798
- const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType;
5948
+ if (primaryKeyColName !== void 0 && primaryKeyColType !== void 0) {
5799
5949
  rowId = AlgebraicType.intoMapKey(
5800
5950
  primaryKeyColType,
5801
5951
  row[primaryKeyColName]
@@ -5876,40 +6026,136 @@ var DbConnectionImpl = class {
5876
6026
  return this.#mergeTableUpdates(updates);
5877
6027
  }
5878
6028
  #flushOutboundQueue(wsResolved) {
6029
+ if (this.#negotiatedWsProtocol === V3_WS_PROTOCOL) {
6030
+ this.#flushOutboundQueueV3(wsResolved);
6031
+ return;
6032
+ }
6033
+ this.#flushOutboundQueueV2(wsResolved);
6034
+ }
6035
+ #flushOutboundQueueV2(wsResolved) {
5879
6036
  const pending = this.#outboundQueue.splice(0);
5880
6037
  for (const message of pending) {
5881
6038
  wsResolved.send(message);
5882
6039
  }
5883
6040
  }
6041
+ #flushOutboundQueueV3(wsResolved) {
6042
+ if (this.#outboundQueue.length === 0) {
6043
+ return;
6044
+ }
6045
+ const batchSize = countClientMessagesForV3Frame(
6046
+ this.#outboundQueue,
6047
+ MAX_V3_OUTBOUND_FRAME_BYTES
6048
+ );
6049
+ wsResolved.send(
6050
+ encodeClientMessagesV3(
6051
+ this.#clientFrameEncoder,
6052
+ this.#outboundQueue,
6053
+ batchSize
6054
+ )
6055
+ );
6056
+ if (batchSize === this.#outboundQueue.length) {
6057
+ this.#outboundQueue.length = 0;
6058
+ return;
6059
+ }
6060
+ this.#outboundQueue.copyWithin(0, batchSize);
6061
+ this.#outboundQueue.length -= batchSize;
6062
+ if (this.#outboundQueue.length > 0) {
6063
+ this.#scheduleDeferredOutboundFlush();
6064
+ }
6065
+ }
6066
+ #scheduleOutboundFlush() {
6067
+ this.#scheduleOutboundFlushWith("microtask");
6068
+ }
6069
+ #scheduleDeferredOutboundFlush() {
6070
+ this.#scheduleOutboundFlushWith("next-task");
6071
+ }
6072
+ #scheduleOutboundFlushWith(schedule) {
6073
+ if (this.#isOutboundFlushScheduled) {
6074
+ return;
6075
+ }
6076
+ this.#isOutboundFlushScheduled = true;
6077
+ const flush = () => {
6078
+ this.#isOutboundFlushScheduled = false;
6079
+ if (this.ws && this.isActive) {
6080
+ this.#flushOutboundQueue(this.ws);
6081
+ }
6082
+ };
6083
+ if (schedule === "next-task") {
6084
+ setTimeout(flush, 0);
6085
+ } else {
6086
+ queueMicrotask(flush);
6087
+ }
6088
+ }
6089
+ #reducerArgsEncoder = new BinaryWriter(1024);
5884
6090
  #clientMessageEncoder = new BinaryWriter(1024);
6091
+ #sendEncodedMessage(encoded, describe) {
6092
+ stdbLogger("trace", describe);
6093
+ if (this.ws && this.isActive) {
6094
+ if (this.#negotiatedWsProtocol === V2_WS_PROTOCOL) {
6095
+ if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
6096
+ this.ws.send(encoded);
6097
+ return;
6098
+ }
6099
+ this.#outboundQueue.push(encoded.slice());
6100
+ this.#scheduleOutboundFlush();
6101
+ } else {
6102
+ this.#outboundQueue.push(encoded.slice());
6103
+ }
6104
+ }
5885
6105
  #sendMessage(message) {
5886
6106
  const writer = this.#clientMessageEncoder;
5887
6107
  writer.clear();
5888
6108
  ClientMessage.serialize(writer, message);
5889
6109
  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
- }
6110
+ const isLive = !!(this.ws && this.isActive);
6111
+ this.#sendEncodedMessage(
6112
+ encoded,
6113
+ () => isLive ? `Sending message to server: ${stringify(message)}` : `Queuing message to server: ${stringify(message)}`
6114
+ );
6115
+ }
6116
+ #sendCallReducerMessage(requestId, reducerNameBytes, argsBuffer) {
6117
+ const writer = this.#clientMessageEncoder;
6118
+ writer.clear();
6119
+ writer.writeByte(CLIENT_MESSAGE_CALL_REDUCER_TAG);
6120
+ writer.writeU32(requestId);
6121
+ writer.writeU8(0);
6122
+ writer.writeUInt8Array(reducerNameBytes);
6123
+ writer.writeUInt8Array(argsBuffer);
6124
+ const encoded = writer.getBuffer();
6125
+ this.#sendEncodedMessage(
6126
+ encoded,
6127
+ () => `Sending reducer call message to server: requestId=${requestId}`
6128
+ );
6129
+ }
6130
+ #sendCallProcedureMessage(requestId, procedureNameBytes, argsBuffer) {
6131
+ const writer = this.#clientMessageEncoder;
6132
+ writer.clear();
6133
+ writer.writeByte(CLIENT_MESSAGE_CALL_PROCEDURE_TAG);
6134
+ writer.writeU32(requestId);
6135
+ writer.writeU8(0);
6136
+ writer.writeUInt8Array(procedureNameBytes);
6137
+ writer.writeUInt8Array(argsBuffer);
6138
+ const encoded = writer.getBuffer();
6139
+ this.#sendEncodedMessage(
6140
+ encoded,
6141
+ () => `Sending procedure call message to server: requestId=${requestId}`
6142
+ );
6143
+ }
6144
+ #setConnectionId(connectionId) {
6145
+ this.connectionId = connectionId;
6146
+ this.#connectionIdHex = connectionId.toHexString();
5904
6147
  }
5905
6148
  #nextEventId() {
5906
6149
  this.#eventId += 1;
5907
- return `${this.connectionId.toHexString()}:${this.#eventId}`;
6150
+ return `${this.#connectionIdHex}:${this.#eventId}`;
5908
6151
  }
5909
6152
  /**
5910
6153
  * Handles WebSocket onOpen event.
5911
6154
  */
5912
6155
  #handleOnOpen() {
6156
+ if (this.ws) {
6157
+ this.#negotiatedWsProtocol = normalizeWsProtocol(this.ws.protocol);
6158
+ }
5913
6159
  this.isActive = true;
5914
6160
  if (this.ws) {
5915
6161
  this.#flushOutboundQueue(this.ws);
@@ -5944,8 +6190,16 @@ var DbConnectionImpl = class {
5944
6190
  eventContext
5945
6191
  );
5946
6192
  }
5947
- async #processMessage(data) {
5948
- const serverMessage = ServerMessage.deserialize(new BinaryReader(data));
6193
+ #dispatchPendingCallbacks(callbacks) {
6194
+ stdbLogger(
6195
+ "trace",
6196
+ () => `Calling ${callbacks.length} triggered row callbacks`
6197
+ );
6198
+ for (const callback of callbacks) {
6199
+ callback.cb();
6200
+ }
6201
+ }
6202
+ #processServerMessage(serverMessage) {
5949
6203
  stdbLogger(
5950
6204
  "trace",
5951
6205
  () => `Processing server message: ${stringify(serverMessage)}`
@@ -5956,7 +6210,7 @@ var DbConnectionImpl = class {
5956
6210
  if (!this.token && serverMessage.value.token) {
5957
6211
  this.token = serverMessage.value.token;
5958
6212
  }
5959
- this.connectionId = serverMessage.value.connectionId;
6213
+ this.#setConnectionId(serverMessage.value.connectionId);
5960
6214
  this.#emitter.emit("connect", this, this.identity, this.token);
5961
6215
  break;
5962
6216
  }
@@ -5982,13 +6236,7 @@ var DbConnectionImpl = class {
5982
6236
  const callbacks = this.#applyTableUpdates(tableUpdates, eventContext);
5983
6237
  const { event: _, ...subscriptionEventContext } = eventContext;
5984
6238
  subscription.emitter.emit("applied", subscriptionEventContext);
5985
- stdbLogger(
5986
- "trace",
5987
- () => `Calling ${callbacks.length} triggered row callbacks`
5988
- );
5989
- for (const callback of callbacks) {
5990
- callback.cb();
5991
- }
6239
+ this.#dispatchPendingCallbacks(callbacks);
5992
6240
  break;
5993
6241
  }
5994
6242
  case "UnsubscribeApplied": {
@@ -6011,13 +6259,7 @@ var DbConnectionImpl = class {
6011
6259
  const { event: _, ...subscriptionEventContext } = eventContext;
6012
6260
  subscription.emitter.emit("end", subscriptionEventContext);
6013
6261
  this.#subscriptionManager.subscriptions.delete(querySetId);
6014
- stdbLogger(
6015
- "trace",
6016
- () => `Calling ${callbacks.length} triggered row callbacks`
6017
- );
6018
- for (const callback of callbacks) {
6019
- callback.cb();
6020
- }
6262
+ this.#dispatchPendingCallbacks(callbacks);
6021
6263
  break;
6022
6264
  }
6023
6265
  case "SubscriptionError": {
@@ -6065,13 +6307,7 @@ var DbConnectionImpl = class {
6065
6307
  eventContext,
6066
6308
  serverMessage.value
6067
6309
  );
6068
- stdbLogger(
6069
- "trace",
6070
- () => `Calling ${callbacks.length} triggered row callbacks`
6071
- );
6072
- for (const callback of callbacks) {
6073
- callback.cb();
6074
- }
6310
+ this.#dispatchPendingCallbacks(callbacks);
6075
6311
  break;
6076
6312
  }
6077
6313
  case "ReducerResult": {
@@ -6099,13 +6335,7 @@ var DbConnectionImpl = class {
6099
6335
  eventContext,
6100
6336
  result.value.transactionUpdate
6101
6337
  );
6102
- stdbLogger(
6103
- "trace",
6104
- () => `Calling ${callbacks.length} triggered row callbacks`
6105
- );
6106
- for (const callback of callbacks) {
6107
- callback.cb();
6108
- }
6338
+ this.#dispatchPendingCallbacks(callbacks);
6109
6339
  }
6110
6340
  this.#reducerCallInfo.delete(requestId);
6111
6341
  const cb = this.#reducerCallbacks.get(requestId);
@@ -6130,14 +6360,55 @@ var DbConnectionImpl = class {
6130
6360
  }
6131
6361
  }
6132
6362
  }
6363
+ #processV2Message(data) {
6364
+ const reader = this.#messageReader;
6365
+ reader.reset(data);
6366
+ this.#processServerMessage(ServerMessage.deserialize(reader));
6367
+ }
6368
+ #processMessage(data) {
6369
+ if (this.#negotiatedWsProtocol !== V3_WS_PROTOCOL) {
6370
+ this.#processV2Message(data);
6371
+ return;
6372
+ }
6373
+ const messageCount = forEachServerMessageV3(
6374
+ this.#messageReader,
6375
+ data,
6376
+ (serverMessage) => {
6377
+ this.#processServerMessage(serverMessage);
6378
+ }
6379
+ );
6380
+ stdbLogger(
6381
+ "trace",
6382
+ () => `Processing server v3 payload with ${messageCount} message(s)`
6383
+ );
6384
+ }
6133
6385
  /**
6134
6386
  * Handles WebSocket onMessage event.
6135
6387
  * @param wsMessage MessageEvent object.
6136
6388
  */
6137
6389
  #handleOnMessage(wsMessage) {
6138
- this.#messageQueue = this.#messageQueue.then(() => {
6139
- return this.#processMessage(wsMessage.data);
6140
- });
6390
+ this.#inboundQueue.push(wsMessage.data);
6391
+ if (this.#isDrainingInboundQueue) {
6392
+ return;
6393
+ }
6394
+ this.#isDrainingInboundQueue = true;
6395
+ try {
6396
+ while (this.#inboundQueueOffset < this.#inboundQueue.length) {
6397
+ const data = this.#inboundQueue[this.#inboundQueueOffset];
6398
+ this.#inboundQueueOffset += 1;
6399
+ if (data) {
6400
+ this.#processMessage(data);
6401
+ }
6402
+ }
6403
+ } finally {
6404
+ if (this.#inboundQueueOffset >= this.#inboundQueue.length) {
6405
+ this.#inboundQueue.length = 0;
6406
+ } else if (this.#inboundQueueOffset > 0) {
6407
+ this.#inboundQueue = this.#inboundQueue.slice(this.#inboundQueueOffset);
6408
+ }
6409
+ this.#inboundQueueOffset = 0;
6410
+ this.#isDrainingInboundQueue = false;
6411
+ }
6141
6412
  }
6142
6413
  /**
6143
6414
  * Call a reducer on your SpacetimeDB module.
@@ -6146,6 +6417,45 @@ var DbConnectionImpl = class {
6146
6417
  * @param argsSerializer The arguments to pass to the reducer
6147
6418
  */
6148
6419
  callReducer(reducerName, argsBuffer, reducerArgs) {
6420
+ const encodedReducerName = this.#reducerNameBytes[reducerName];
6421
+ if (encodedReducerName) {
6422
+ return this.#callReducerWithEncodedName(
6423
+ reducerName,
6424
+ encodedReducerName,
6425
+ argsBuffer,
6426
+ reducerArgs
6427
+ );
6428
+ }
6429
+ return this.#callReducerGeneric(reducerName, argsBuffer, reducerArgs);
6430
+ }
6431
+ #callReducerWithEncodedName(reducerName, encodedReducerName, argsBuffer, reducerArgs) {
6432
+ const { promise, resolve, reject } = Promise.withResolvers();
6433
+ const requestId = this.#getNextRequestId();
6434
+ this.#sendCallReducerMessage(requestId, encodedReducerName, argsBuffer);
6435
+ if (reducerArgs) {
6436
+ this.#reducerCallInfo.set(requestId, {
6437
+ name: reducerName,
6438
+ args: reducerArgs
6439
+ });
6440
+ }
6441
+ this.#reducerCallbacks.set(requestId, (result) => {
6442
+ if (result.tag === "Ok" || result.tag === "OkEmpty") {
6443
+ resolve();
6444
+ } else {
6445
+ if (result.tag === "Err") {
6446
+ const reader = new BinaryReader(result.value);
6447
+ const errorString = reader.readString();
6448
+ reject(new SenderError(errorString));
6449
+ } else if (result.tag === "InternalError") {
6450
+ reject(new InternalError(result.value));
6451
+ } else {
6452
+ reject(new Error("Unexpected reducer result"));
6453
+ }
6454
+ }
6455
+ });
6456
+ return promise;
6457
+ }
6458
+ #callReducerGeneric(reducerName, argsBuffer, reducerArgs) {
6149
6459
  const { promise, resolve, reject } = Promise.withResolvers();
6150
6460
  const requestId = this.#getNextRequestId();
6151
6461
  const message = ClientMessage.CallReducer({
@@ -6185,7 +6495,8 @@ var DbConnectionImpl = class {
6185
6495
  * @param params The arguments to pass to the reducer
6186
6496
  */
6187
6497
  callReducerWithParams(reducerName, _paramsType, params) {
6188
- const writer = new BinaryWriter(1024);
6498
+ const writer = this.#reducerArgsEncoder;
6499
+ writer.clear();
6189
6500
  this.#reducerArgsSerializers[reducerName].serialize(writer, params);
6190
6501
  const argsBuffer = writer.getBuffer();
6191
6502
  return this.callReducer(reducerName, argsBuffer, params);
@@ -6197,6 +6508,30 @@ var DbConnectionImpl = class {
6197
6508
  * @param argsBuffer The arguments to pass to the reducer
6198
6509
  */
6199
6510
  callProcedure(procedureName, argsBuffer) {
6511
+ const encodedProcedureName = this.#procedureNameBytes[procedureName];
6512
+ if (encodedProcedureName) {
6513
+ return this.#callProcedureWithEncodedName(
6514
+ procedureName,
6515
+ encodedProcedureName,
6516
+ argsBuffer
6517
+ );
6518
+ }
6519
+ return this.#callProcedureGeneric(procedureName, argsBuffer);
6520
+ }
6521
+ #callProcedureWithEncodedName(procedureName, encodedProcedureName, argsBuffer) {
6522
+ const { promise, resolve, reject } = Promise.withResolvers();
6523
+ const requestId = this.#getNextRequestId();
6524
+ this.#sendCallProcedureMessage(requestId, encodedProcedureName, argsBuffer);
6525
+ this.#procedureCallbacks.set(requestId, (result) => {
6526
+ if (result.tag === "Ok") {
6527
+ resolve(result.value);
6528
+ } else {
6529
+ reject(result.value);
6530
+ }
6531
+ });
6532
+ return promise;
6533
+ }
6534
+ #callProcedureGeneric(procedureName, argsBuffer) {
6200
6535
  const { promise, resolve, reject } = Promise.withResolvers();
6201
6536
  const requestId = this.#getNextRequestId();
6202
6537
  const message = ClientMessage.CallProcedure({
@@ -7137,7 +7472,7 @@ function table(opts, row, ..._) {
7137
7472
  increment: 1n
7138
7473
  });
7139
7474
  }
7140
- if (meta.defaultValue) {
7475
+ if (Object.prototype.hasOwnProperty.call(meta, "defaultValue")) {
7141
7476
  const writer = new BinaryWriter(16);
7142
7477
  builder.serialize(writer, meta.defaultValue);
7143
7478
  defaultValues.push({