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