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.
- package/LICENSE.txt +2 -2
- package/dist/angular/index.cjs +9 -3
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.mjs +9 -3
- package/dist/angular/index.mjs.map +1 -1
- package/dist/browser/angular/index.mjs +9 -3
- package/dist/browser/angular/index.mjs.map +1 -1
- package/dist/browser/react/index.mjs +62 -7
- package/dist/browser/react/index.mjs.map +1 -1
- package/dist/browser/svelte/index.mjs +9 -3
- package/dist/browser/svelte/index.mjs.map +1 -1
- package/dist/browser/vue/index.mjs +9 -3
- package/dist/browser/vue/index.mjs.map +1 -1
- package/dist/index.browser.mjs +481 -146
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +481 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +481 -146
- package/dist/index.mjs.map +1 -1
- package/dist/lib/algebraic_type.d.ts.map +1 -1
- package/dist/lib/binary_reader.d.ts +1 -1
- package/dist/lib/binary_reader.d.ts.map +1 -1
- package/dist/lib/binary_writer.d.ts +2 -1
- package/dist/lib/binary_writer.d.ts.map +1 -1
- package/dist/lib/filter.d.ts +2 -1
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/query.d.ts +10 -5
- package/dist/lib/query.d.ts.map +1 -1
- package/dist/lib/table.d.ts +12 -1
- package/dist/lib/table.d.ts.map +1 -1
- package/dist/min/index.browser.mjs +1 -1
- package/dist/min/index.browser.mjs.map +1 -1
- package/dist/min/react/index.mjs +1 -1
- package/dist/min/react/index.mjs.map +1 -1
- package/dist/min/sdk/index.browser.mjs +1 -1
- package/dist/min/sdk/index.browser.mjs.map +1 -1
- package/dist/react/index.cjs +62 -6
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.mjs +62 -7
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useProcedure.d.ts +4 -0
- package/dist/react/useProcedure.d.ts.map +1 -0
- package/dist/react/useTable.d.ts +2 -0
- package/dist/react/useTable.d.ts.map +1 -1
- package/dist/sdk/db_connection_builder.d.ts +3 -3
- package/dist/sdk/db_connection_builder.d.ts.map +1 -1
- package/dist/sdk/db_connection_impl.d.ts +3 -3
- package/dist/sdk/db_connection_impl.d.ts.map +1 -1
- package/dist/sdk/decompress.d.ts +1 -1
- package/dist/sdk/decompress.d.ts.map +1 -1
- package/dist/sdk/index.browser.mjs +477 -144
- package/dist/sdk/index.browser.mjs.map +1 -1
- package/dist/sdk/index.cjs +477 -144
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.mjs +477 -144
- package/dist/sdk/index.mjs.map +1 -1
- package/dist/sdk/table_cache.d.ts +1 -0
- package/dist/sdk/table_cache.d.ts.map +1 -1
- package/dist/sdk/type_utils.d.ts +4 -1
- package/dist/sdk/type_utils.d.ts.map +1 -1
- package/dist/sdk/websocket_decompress_adapter.d.ts +5 -21
- package/dist/sdk/websocket_decompress_adapter.d.ts.map +1 -1
- package/dist/sdk/websocket_protocols.d.ts +6 -0
- package/dist/sdk/websocket_protocols.d.ts.map +1 -0
- package/dist/sdk/websocket_test_adapter.d.ts +14 -18
- package/dist/sdk/websocket_test_adapter.d.ts.map +1 -1
- package/dist/sdk/websocket_v3_frames.d.ts +9 -0
- package/dist/sdk/websocket_v3_frames.d.ts.map +1 -0
- package/dist/sdk/ws.d.ts +26 -1
- package/dist/sdk/ws.d.ts.map +1 -1
- package/dist/server/http_internal.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.mjs +76 -15
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/runtime.d.ts +29 -2
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/svelte/index.cjs +9 -3
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.mjs +9 -3
- package/dist/svelte/index.mjs.map +1 -1
- package/dist/tanstack/index.cjs +9 -3
- package/dist/tanstack/index.cjs.map +1 -1
- package/dist/tanstack/index.mjs +9 -3
- package/dist/tanstack/index.mjs.map +1 -1
- package/dist/vue/index.cjs +9 -3
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.mjs +9 -3
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/lib/algebraic_type.ts +5 -1
- package/src/lib/binary_reader.ts +5 -2
- package/src/lib/binary_writer.ts +7 -1
- package/src/lib/filter.ts +12 -1
- package/src/lib/query.ts +60 -19
- package/src/lib/table.ts +15 -2
- package/src/react/index.ts +1 -0
- package/src/react/useProcedure.ts +60 -0
- package/src/react/useTable.ts +22 -2
- package/src/sdk/db_connection_builder.ts +16 -7
- package/src/sdk/db_connection_impl.ts +404 -89
- package/src/sdk/decompress.ts +7 -23
- package/src/sdk/table_cache.ts +5 -5
- package/src/sdk/type_utils.ts +10 -1
- package/src/sdk/websocket_decompress_adapter.ts +15 -77
- package/src/sdk/websocket_protocols.ts +25 -0
- package/src/sdk/websocket_test_adapter.ts +65 -29
- package/src/sdk/websocket_v3_frames.ts +126 -0
- package/src/sdk/ws.ts +81 -3
- package/src/server/http_internal.ts +10 -1
- package/src/server/index.ts +2 -1
- package/src/server/runtime.ts +39 -1
- package/src/server/sys.d.ts +4 -0
- package/src/server/view.test-d.ts +4 -0
package/dist/sdk/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(
|
|
432
|
-
this.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);
|
|
@@ -1177,7 +1182,8 @@ writer.offset += ${primitiveSizes[tag]};` : `writer.write${tag}(value.${name});`
|
|
|
1177
1182
|
const result = { ${ty.elements.map(getElementInitializer).join(", ")} };
|
|
1178
1183
|
const view = reader.view;
|
|
1179
1184
|
${ty.elements.map(
|
|
1180
|
-
({ name, algebraicType: { tag } }) => tag in primitiveJSName ? `result.${name} = view.
|
|
1185
|
+
({ name, algebraicType: { tag } }) => tag in primitiveJSName ? tag === "Bool" ? `result.${name} = view.getUint8(reader.offset) !== 0;
|
|
1186
|
+
reader.offset += 1;` : `result.${name} = view.get${primitiveJSName[tag]}(reader.offset, ${primitiveSizes[tag] > 1 ? "true" : ""});
|
|
1181
1187
|
reader.offset += ${primitiveSizes[tag]};` : `result.${name} = reader.read${tag}();`
|
|
1182
1188
|
).join("\n")}
|
|
1183
1189
|
return result;`;
|
|
@@ -1673,7 +1679,8 @@ function createRowExpr(tableDef) {
|
|
|
1673
1679
|
const column = new ColumnExpression(
|
|
1674
1680
|
tableDef.sourceName,
|
|
1675
1681
|
columnName,
|
|
1676
|
-
columnBuilder.typeBuilder.algebraicType
|
|
1682
|
+
columnBuilder.typeBuilder.algebraicType,
|
|
1683
|
+
columnBuilder.columnMetadata.name
|
|
1677
1684
|
);
|
|
1678
1685
|
row[columnName] = Object.freeze(column);
|
|
1679
1686
|
}
|
|
@@ -1691,14 +1698,18 @@ function renderSelectSqlWithJoins(table2, where, extraClauses = []) {
|
|
|
1691
1698
|
}
|
|
1692
1699
|
var ColumnExpression = class {
|
|
1693
1700
|
type = "column";
|
|
1701
|
+
// This is the column accessor
|
|
1694
1702
|
column;
|
|
1703
|
+
// The name of the column in the database.
|
|
1704
|
+
columnName;
|
|
1695
1705
|
table;
|
|
1696
1706
|
// phantom: actual runtime value is undefined
|
|
1697
1707
|
tsValueType;
|
|
1698
1708
|
spacetimeType;
|
|
1699
|
-
constructor(table2, column, spacetimeType) {
|
|
1709
|
+
constructor(table2, column, spacetimeType, columnName) {
|
|
1700
1710
|
this.table = table2;
|
|
1701
1711
|
this.column = column;
|
|
1712
|
+
this.columnName = columnName || column;
|
|
1702
1713
|
this.spacetimeType = spacetimeType;
|
|
1703
1714
|
}
|
|
1704
1715
|
eq(x) {
|
|
@@ -1775,10 +1786,16 @@ var BooleanExpr = class _BooleanExpr {
|
|
|
1775
1786
|
this.data = data;
|
|
1776
1787
|
}
|
|
1777
1788
|
and(other) {
|
|
1778
|
-
return new _BooleanExpr({
|
|
1789
|
+
return new _BooleanExpr({
|
|
1790
|
+
type: "and",
|
|
1791
|
+
clauses: [this.data, other.data]
|
|
1792
|
+
});
|
|
1779
1793
|
}
|
|
1780
1794
|
or(other) {
|
|
1781
|
-
return new _BooleanExpr({
|
|
1795
|
+
return new _BooleanExpr({
|
|
1796
|
+
type: "or",
|
|
1797
|
+
clauses: [this.data, other.data]
|
|
1798
|
+
});
|
|
1782
1799
|
}
|
|
1783
1800
|
not() {
|
|
1784
1801
|
return new _BooleanExpr({ type: "not", clause: this.data });
|
|
@@ -1815,7 +1832,7 @@ function valueExprToSql(expr, tableAlias) {
|
|
|
1815
1832
|
return literalValueToSql(expr.value);
|
|
1816
1833
|
}
|
|
1817
1834
|
const table2 = expr.table;
|
|
1818
|
-
return `${quoteIdentifier(table2)}.${quoteIdentifier(expr.
|
|
1835
|
+
return `${quoteIdentifier(table2)}.${quoteIdentifier(expr.columnName)}`;
|
|
1819
1836
|
}
|
|
1820
1837
|
function literalValueToSql(value) {
|
|
1821
1838
|
if (value === null || value === void 0) {
|
|
@@ -4318,6 +4335,7 @@ var scalarCompare = (x, y) => {
|
|
|
4318
4335
|
return x < y ? -1 : 1;
|
|
4319
4336
|
};
|
|
4320
4337
|
var TableCacheImpl = class {
|
|
4338
|
+
hasPrimaryKey;
|
|
4321
4339
|
rows;
|
|
4322
4340
|
tableDef;
|
|
4323
4341
|
emitter;
|
|
@@ -4331,6 +4349,9 @@ var TableCacheImpl = class {
|
|
|
4331
4349
|
this.tableDef = tableDef;
|
|
4332
4350
|
this.rows = /* @__PURE__ */ new Map();
|
|
4333
4351
|
this.emitter = new EventEmitter();
|
|
4352
|
+
this.hasPrimaryKey = Object.values(this.tableDef.columns).some(
|
|
4353
|
+
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4354
|
+
);
|
|
4334
4355
|
for (const idxDef of this.tableDef.resolvedIndexes) {
|
|
4335
4356
|
const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
|
|
4336
4357
|
this[idxDef.name] = index;
|
|
@@ -4440,10 +4461,7 @@ var TableCacheImpl = class {
|
|
|
4440
4461
|
}
|
|
4441
4462
|
return pendingCallbacks;
|
|
4442
4463
|
}
|
|
4443
|
-
|
|
4444
|
-
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4445
|
-
);
|
|
4446
|
-
if (hasPrimaryKey) {
|
|
4464
|
+
if (this.hasPrimaryKey) {
|
|
4447
4465
|
const insertMap = /* @__PURE__ */ new Map();
|
|
4448
4466
|
const deleteMap = /* @__PURE__ */ new Map();
|
|
4449
4467
|
for (const op of operations) {
|
|
@@ -4851,27 +4869,17 @@ async function decompress(buffer, type, chunkSize = 128 * 1024) {
|
|
|
4851
4869
|
});
|
|
4852
4870
|
const decompressionStream = new DecompressionStream(type);
|
|
4853
4871
|
const decompressedStream = readableStream.pipeThrough(decompressionStream);
|
|
4854
|
-
const reader = decompressedStream.getReader();
|
|
4855
4872
|
const chunks = [];
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
totalLength += result.value.length;
|
|
4861
|
-
}
|
|
4862
|
-
const decompressedArray = new Uint8Array(totalLength);
|
|
4863
|
-
let chunkOffset = 0;
|
|
4864
|
-
for (const chunk of chunks) {
|
|
4865
|
-
decompressedArray.set(chunk, chunkOffset);
|
|
4866
|
-
chunkOffset += chunk.length;
|
|
4867
|
-
}
|
|
4868
|
-
return decompressedArray;
|
|
4873
|
+
for await (const chunk of decompressedStream) {
|
|
4874
|
+
chunks.push(chunk);
|
|
4875
|
+
}
|
|
4876
|
+
return new Blob(chunks).bytes();
|
|
4869
4877
|
}
|
|
4870
4878
|
|
|
4871
4879
|
// src/sdk/ws.ts
|
|
4872
4880
|
async function resolveWS() {
|
|
4873
|
-
if (typeof
|
|
4874
|
-
return
|
|
4881
|
+
if (typeof WebSocket !== "undefined") {
|
|
4882
|
+
return WebSocket;
|
|
4875
4883
|
}
|
|
4876
4884
|
const dynamicImport = new Function("m", "return import(m)");
|
|
4877
4885
|
try {
|
|
@@ -4885,9 +4893,54 @@ async function resolveWS() {
|
|
|
4885
4893
|
throw err;
|
|
4886
4894
|
}
|
|
4887
4895
|
}
|
|
4896
|
+
async function openWebSocket({
|
|
4897
|
+
url,
|
|
4898
|
+
nameOrAddress,
|
|
4899
|
+
wsProtocol,
|
|
4900
|
+
authToken,
|
|
4901
|
+
compression,
|
|
4902
|
+
lightMode,
|
|
4903
|
+
confirmedReads
|
|
4904
|
+
}) {
|
|
4905
|
+
const headers = new Headers();
|
|
4906
|
+
const WS = await resolveWS();
|
|
4907
|
+
let temporaryAuthToken;
|
|
4908
|
+
if (authToken) {
|
|
4909
|
+
headers.set("Authorization", `Bearer ${authToken}`);
|
|
4910
|
+
const tokenUrl = new URL("v1/identity/websocket-token", url);
|
|
4911
|
+
tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
4912
|
+
const response = await fetch(tokenUrl, { method: "POST", headers });
|
|
4913
|
+
if (response.ok) {
|
|
4914
|
+
const { token } = await response.json();
|
|
4915
|
+
temporaryAuthToken = token;
|
|
4916
|
+
} else {
|
|
4917
|
+
throw new Error(`Failed to verify token: ${response.statusText}`);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
|
|
4921
|
+
if (temporaryAuthToken) {
|
|
4922
|
+
databaseUrl.searchParams.set("token", temporaryAuthToken);
|
|
4923
|
+
}
|
|
4924
|
+
databaseUrl.searchParams.set(
|
|
4925
|
+
"compression",
|
|
4926
|
+
{ gzip: "Gzip", brotli: "Brotli", none: "None" }[compression] ?? "None"
|
|
4927
|
+
);
|
|
4928
|
+
if (lightMode) {
|
|
4929
|
+
databaseUrl.searchParams.set("light", "true");
|
|
4930
|
+
}
|
|
4931
|
+
if (confirmedReads !== void 0) {
|
|
4932
|
+
databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
|
|
4933
|
+
}
|
|
4934
|
+
const ws = new WS(databaseUrl.toString(), wsProtocol);
|
|
4935
|
+
ws.binaryType = "arraybuffer";
|
|
4936
|
+
return ws;
|
|
4937
|
+
}
|
|
4888
4938
|
|
|
4889
4939
|
// src/sdk/websocket_decompress_adapter.ts
|
|
4890
4940
|
var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
4941
|
+
get protocol() {
|
|
4942
|
+
return this.#ws.protocol;
|
|
4943
|
+
}
|
|
4891
4944
|
set onclose(handler) {
|
|
4892
4945
|
this.#ws.onclose = handler;
|
|
4893
4946
|
}
|
|
@@ -4911,9 +4964,7 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
4911
4964
|
case 0:
|
|
4912
4965
|
return data;
|
|
4913
4966
|
case 1:
|
|
4914
|
-
|
|
4915
|
-
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
4916
|
-
);
|
|
4967
|
+
return await decompress(data, "brotli");
|
|
4917
4968
|
case 2:
|
|
4918
4969
|
return await decompress(data, "gzip");
|
|
4919
4970
|
default:
|
|
@@ -4929,51 +4980,10 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
4929
4980
|
this.#ws.close();
|
|
4930
4981
|
}
|
|
4931
4982
|
constructor(ws) {
|
|
4932
|
-
ws.binaryType = "arraybuffer";
|
|
4933
4983
|
this.#ws = ws;
|
|
4934
4984
|
}
|
|
4935
|
-
static async
|
|
4936
|
-
|
|
4937
|
-
nameOrAddress,
|
|
4938
|
-
wsProtocol,
|
|
4939
|
-
authToken,
|
|
4940
|
-
compression,
|
|
4941
|
-
lightMode,
|
|
4942
|
-
confirmedReads
|
|
4943
|
-
}) {
|
|
4944
|
-
const headers = new Headers();
|
|
4945
|
-
const WS = await resolveWS();
|
|
4946
|
-
let temporaryAuthToken = void 0;
|
|
4947
|
-
if (authToken) {
|
|
4948
|
-
headers.set("Authorization", `Bearer ${authToken}`);
|
|
4949
|
-
const tokenUrl = new URL("v1/identity/websocket-token", url);
|
|
4950
|
-
tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
4951
|
-
const response = await fetch(tokenUrl, { method: "POST", headers });
|
|
4952
|
-
if (response.ok) {
|
|
4953
|
-
const { token } = await response.json();
|
|
4954
|
-
temporaryAuthToken = token;
|
|
4955
|
-
} else {
|
|
4956
|
-
return Promise.reject(
|
|
4957
|
-
new Error(`Failed to verify token: ${response.statusText}`)
|
|
4958
|
-
);
|
|
4959
|
-
}
|
|
4960
|
-
}
|
|
4961
|
-
const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
|
|
4962
|
-
if (temporaryAuthToken) {
|
|
4963
|
-
databaseUrl.searchParams.set("token", temporaryAuthToken);
|
|
4964
|
-
}
|
|
4965
|
-
databaseUrl.searchParams.set(
|
|
4966
|
-
"compression",
|
|
4967
|
-
compression === "gzip" ? "Gzip" : "None"
|
|
4968
|
-
);
|
|
4969
|
-
if (lightMode) {
|
|
4970
|
-
databaseUrl.searchParams.set("light", "true");
|
|
4971
|
-
}
|
|
4972
|
-
if (confirmedReads !== void 0) {
|
|
4973
|
-
databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
|
|
4974
|
-
}
|
|
4975
|
-
const ws = new WS(databaseUrl.toString(), wsProtocol);
|
|
4976
|
-
return new _WebsocketDecompressAdapter(ws);
|
|
4985
|
+
static async openWebSocket(args) {
|
|
4986
|
+
return new _WebsocketDecompressAdapter(await openWebSocket(args));
|
|
4977
4987
|
}
|
|
4978
4988
|
};
|
|
4979
4989
|
|
|
@@ -4990,7 +5000,7 @@ var DbConnectionBuilder = class {
|
|
|
4990
5000
|
constructor(remoteModule, dbConnectionCtor) {
|
|
4991
5001
|
this.remoteModule = remoteModule;
|
|
4992
5002
|
this.dbConnectionCtor = dbConnectionCtor;
|
|
4993
|
-
this.#createWSFn = WebsocketDecompressAdapter.
|
|
5003
|
+
this.#createWSFn = WebsocketDecompressAdapter.openWebSocket;
|
|
4994
5004
|
}
|
|
4995
5005
|
#uri;
|
|
4996
5006
|
#nameOrAddress;
|
|
@@ -5045,6 +5055,16 @@ var DbConnectionBuilder = class {
|
|
|
5045
5055
|
* @param compression The compression algorithm to use for the connection.
|
|
5046
5056
|
*/
|
|
5047
5057
|
withCompression(compression) {
|
|
5058
|
+
if (compression === "brotli") {
|
|
5059
|
+
try {
|
|
5060
|
+
new DecompressionStream("brotli");
|
|
5061
|
+
} catch (e) {
|
|
5062
|
+
throw new TypeError(
|
|
5063
|
+
`Brotli compression is not supported by the runtime. Please choose a different compression method.`,
|
|
5064
|
+
{ cause: e }
|
|
5065
|
+
);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5048
5068
|
this.#compression = compression;
|
|
5049
5069
|
return this;
|
|
5050
5070
|
}
|
|
@@ -5408,6 +5428,100 @@ var SubscriptionHandleImpl = class {
|
|
|
5408
5428
|
return this.#activeState;
|
|
5409
5429
|
}
|
|
5410
5430
|
};
|
|
5431
|
+
|
|
5432
|
+
// src/sdk/websocket_protocols.ts
|
|
5433
|
+
var V2_WS_PROTOCOL = "v2.bsatn.spacetimedb";
|
|
5434
|
+
var V3_WS_PROTOCOL = "v3.bsatn.spacetimedb";
|
|
5435
|
+
var PREFERRED_WS_PROTOCOLS = [V3_WS_PROTOCOL, V2_WS_PROTOCOL];
|
|
5436
|
+
function normalizeWsProtocol(protocol) {
|
|
5437
|
+
if (protocol === V3_WS_PROTOCOL) {
|
|
5438
|
+
return V3_WS_PROTOCOL;
|
|
5439
|
+
}
|
|
5440
|
+
if (protocol === "" || protocol === V2_WS_PROTOCOL) {
|
|
5441
|
+
return V2_WS_PROTOCOL;
|
|
5442
|
+
}
|
|
5443
|
+
stdbLogger(
|
|
5444
|
+
"warn",
|
|
5445
|
+
`Unexpected websocket subprotocol "${protocol}", falling back to ${V2_WS_PROTOCOL}.`
|
|
5446
|
+
);
|
|
5447
|
+
return V2_WS_PROTOCOL;
|
|
5448
|
+
}
|
|
5449
|
+
|
|
5450
|
+
// src/sdk/websocket_v3_frames.ts
|
|
5451
|
+
var EMPTY_V3_PAYLOAD_ERR = "v3 websocket payloads must contain at least one message";
|
|
5452
|
+
function ensureMessages(messages) {
|
|
5453
|
+
if (messages.length === 0) {
|
|
5454
|
+
throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
function ensureMessageCount(messages, messageCount) {
|
|
5458
|
+
ensureMessages(messages);
|
|
5459
|
+
if (messageCount < 1 || messageCount > messages.length) {
|
|
5460
|
+
throw new RangeError(
|
|
5461
|
+
`v3 websocket payload requested ${messageCount} messages from ${messages.length}`
|
|
5462
|
+
);
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
function concatenateMessagesV3(writer, messages, messageCount = messages.length) {
|
|
5466
|
+
ensureMessageCount(messages, messageCount);
|
|
5467
|
+
writer.clear();
|
|
5468
|
+
for (let i = 0; i < messageCount; i++) {
|
|
5469
|
+
writer.writeBytes(messages[i]);
|
|
5470
|
+
}
|
|
5471
|
+
return writer.getBuffer();
|
|
5472
|
+
}
|
|
5473
|
+
function countClientMessagesForV3Frame(messages, maxFrameBytes) {
|
|
5474
|
+
ensureMessages(messages);
|
|
5475
|
+
const firstMessage = messages[0];
|
|
5476
|
+
if (firstMessage.length > maxFrameBytes) {
|
|
5477
|
+
return 1;
|
|
5478
|
+
}
|
|
5479
|
+
let count = 1;
|
|
5480
|
+
let frameSize = firstMessage.length;
|
|
5481
|
+
while (count < messages.length) {
|
|
5482
|
+
const nextMessage = messages[count];
|
|
5483
|
+
const nextFrameSize = frameSize + nextMessage.length;
|
|
5484
|
+
if (nextFrameSize > maxFrameBytes) {
|
|
5485
|
+
break;
|
|
5486
|
+
}
|
|
5487
|
+
frameSize = nextFrameSize;
|
|
5488
|
+
count += 1;
|
|
5489
|
+
}
|
|
5490
|
+
return count;
|
|
5491
|
+
}
|
|
5492
|
+
function encodeClientMessagesV3(writer, messages, messageCount = messages.length) {
|
|
5493
|
+
return concatenateMessagesV3(writer, messages, messageCount);
|
|
5494
|
+
}
|
|
5495
|
+
function forEachServerMessageV3(reader, data, visit) {
|
|
5496
|
+
reader.reset(data);
|
|
5497
|
+
if (reader.remaining === 0) {
|
|
5498
|
+
throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
|
|
5499
|
+
}
|
|
5500
|
+
let count = 0;
|
|
5501
|
+
while (reader.remaining > 0) {
|
|
5502
|
+
visit(ServerMessage.deserialize(reader));
|
|
5503
|
+
count += 1;
|
|
5504
|
+
}
|
|
5505
|
+
return count;
|
|
5506
|
+
}
|
|
5507
|
+
|
|
5508
|
+
// src/sdk/db_connection_impl.ts
|
|
5509
|
+
var TEXT_ENCODER = new TextEncoder();
|
|
5510
|
+
function getClientMessageVariantTag(name) {
|
|
5511
|
+
if (ClientMessage.algebraicType.tag !== "Sum") {
|
|
5512
|
+
throw new TypeError("ClientMessage must be a sum type");
|
|
5513
|
+
}
|
|
5514
|
+
const tag = ClientMessage.algebraicType.value.variants.findIndex(
|
|
5515
|
+
(variant) => variant.name === name
|
|
5516
|
+
);
|
|
5517
|
+
if (tag === -1) {
|
|
5518
|
+
throw new RangeError(`Unknown ClientMessage variant: ${name}`);
|
|
5519
|
+
}
|
|
5520
|
+
return tag;
|
|
5521
|
+
}
|
|
5522
|
+
var CLIENT_MESSAGE_CALL_REDUCER_TAG = getClientMessageVariantTag("CallReducer");
|
|
5523
|
+
var CLIENT_MESSAGE_CALL_PROCEDURE_TAG = getClientMessageVariantTag("CallProcedure");
|
|
5524
|
+
var MAX_V3_OUTBOUND_FRAME_BYTES = 256 * 1024;
|
|
5411
5525
|
var DbConnectionImpl = class {
|
|
5412
5526
|
/**
|
|
5413
5527
|
* Whether or not the connection is active.
|
|
@@ -5442,22 +5556,35 @@ var DbConnectionImpl = class {
|
|
|
5442
5556
|
* The `ConnectionId` of the connection to to the database.
|
|
5443
5557
|
*/
|
|
5444
5558
|
connectionId = ConnectionId.random();
|
|
5559
|
+
#connectionIdHex = this.connectionId.toHexString();
|
|
5445
5560
|
// These fields are meant to be strictly private.
|
|
5446
5561
|
#queryId = 0;
|
|
5447
5562
|
#requestId = 0;
|
|
5448
5563
|
#eventId = 0;
|
|
5449
5564
|
#emitter;
|
|
5450
|
-
#
|
|
5565
|
+
#inboundQueue = [];
|
|
5566
|
+
#inboundQueueOffset = 0;
|
|
5567
|
+
#isDrainingInboundQueue = false;
|
|
5451
5568
|
#outboundQueue = [];
|
|
5569
|
+
#isOutboundFlushScheduled = false;
|
|
5570
|
+
#negotiatedWsProtocol = V2_WS_PROTOCOL;
|
|
5452
5571
|
#subscriptionManager = new SubscriptionManager();
|
|
5453
5572
|
#remoteModule;
|
|
5454
5573
|
#reducerCallbacks = /* @__PURE__ */ new Map();
|
|
5455
5574
|
#reducerCallInfo = /* @__PURE__ */ new Map();
|
|
5456
5575
|
#procedureCallbacks = /* @__PURE__ */ new Map();
|
|
5457
5576
|
#rowDeserializers;
|
|
5577
|
+
#rowIdMetadata;
|
|
5458
5578
|
#reducerArgsSerializers;
|
|
5459
5579
|
#procedureSerializers;
|
|
5580
|
+
#reducerNameBytes;
|
|
5581
|
+
#procedureNameBytes;
|
|
5460
5582
|
#sourceNameToTableDef;
|
|
5583
|
+
#messageReader = new BinaryReader(new Uint8Array());
|
|
5584
|
+
#rowListReader = new BinaryReader(new Uint8Array());
|
|
5585
|
+
#clientFrameEncoder = new BinaryWriter(1024);
|
|
5586
|
+
#boundSubscriptionBuilder;
|
|
5587
|
+
#boundDisconnect;
|
|
5461
5588
|
// These fields are not part of the public API, but in a pinch you
|
|
5462
5589
|
// could use JavaScript to access them by bypassing TypeScript's
|
|
5463
5590
|
// private fields.
|
|
@@ -5486,22 +5613,35 @@ var DbConnectionImpl = class {
|
|
|
5486
5613
|
this.token = token;
|
|
5487
5614
|
this.#remoteModule = remoteModule;
|
|
5488
5615
|
this.#emitter = emitter;
|
|
5616
|
+
this.#boundSubscriptionBuilder = this.subscriptionBuilder.bind(this);
|
|
5617
|
+
this.#boundDisconnect = this.disconnect.bind(this);
|
|
5489
5618
|
this.#rowDeserializers = /* @__PURE__ */ Object.create(null);
|
|
5619
|
+
this.#rowIdMetadata = /* @__PURE__ */ Object.create(null);
|
|
5490
5620
|
this.#sourceNameToTableDef = /* @__PURE__ */ Object.create(null);
|
|
5491
5621
|
for (const table2 of Object.values(remoteModule.tables)) {
|
|
5492
5622
|
this.#rowDeserializers[table2.sourceName] = ProductType.makeDeserializer(
|
|
5493
5623
|
table2.rowType
|
|
5494
5624
|
);
|
|
5495
5625
|
this.#sourceNameToTableDef[table2.sourceName] = table2;
|
|
5626
|
+
const primaryKeyColumn = Object.entries(table2.columns).find(
|
|
5627
|
+
([, column]) => column.columnMetadata.isPrimaryKey
|
|
5628
|
+
);
|
|
5629
|
+
this.#rowIdMetadata[table2.sourceName] = primaryKeyColumn ? {
|
|
5630
|
+
primaryKeyColName: primaryKeyColumn[0],
|
|
5631
|
+
primaryKeyColType: primaryKeyColumn[1].typeBuilder.algebraicType
|
|
5632
|
+
} : {};
|
|
5496
5633
|
}
|
|
5497
5634
|
this.#reducerArgsSerializers = /* @__PURE__ */ Object.create(null);
|
|
5635
|
+
this.#reducerNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5498
5636
|
for (const reducer of remoteModule.reducers) {
|
|
5499
5637
|
this.#reducerArgsSerializers[reducer.name] = {
|
|
5500
5638
|
serialize: ProductType.makeSerializer(reducer.paramsType),
|
|
5501
5639
|
deserialize: ProductType.makeDeserializer(reducer.paramsType)
|
|
5502
5640
|
};
|
|
5641
|
+
this.#reducerNameBytes[reducer.name] = TEXT_ENCODER.encode(reducer.name);
|
|
5503
5642
|
}
|
|
5504
5643
|
this.#procedureSerializers = /* @__PURE__ */ Object.create(null);
|
|
5644
|
+
this.#procedureNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5505
5645
|
for (const procedure of remoteModule.procedures) {
|
|
5506
5646
|
this.#procedureSerializers[procedure.name] = {
|
|
5507
5647
|
serializeArgs: ProductType.makeSerializer(
|
|
@@ -5511,9 +5651,11 @@ var DbConnectionImpl = class {
|
|
|
5511
5651
|
procedure.returnType.algebraicType
|
|
5512
5652
|
)
|
|
5513
5653
|
};
|
|
5654
|
+
this.#procedureNameBytes[procedure.name] = TEXT_ENCODER.encode(
|
|
5655
|
+
procedure.name
|
|
5656
|
+
);
|
|
5514
5657
|
}
|
|
5515
|
-
|
|
5516
|
-
url.searchParams.set("connection_id", connectionId);
|
|
5658
|
+
url.searchParams.set("connection_id", this.#connectionIdHex);
|
|
5517
5659
|
this.clientCache = new ClientCache();
|
|
5518
5660
|
this.db = this.#makeDbView();
|
|
5519
5661
|
this.reducers = this.#makeReducers(remoteModule);
|
|
@@ -5521,7 +5663,7 @@ var DbConnectionImpl = class {
|
|
|
5521
5663
|
this.wsPromise = createWSFn({
|
|
5522
5664
|
url,
|
|
5523
5665
|
nameOrAddress,
|
|
5524
|
-
wsProtocol:
|
|
5666
|
+
wsProtocol: [...PREFERRED_WS_PROTOCOLS],
|
|
5525
5667
|
authToken: token,
|
|
5526
5668
|
compression,
|
|
5527
5669
|
lightMode,
|
|
@@ -5565,16 +5707,22 @@ var DbConnectionImpl = class {
|
|
|
5565
5707
|
}
|
|
5566
5708
|
#makeReducers(def) {
|
|
5567
5709
|
const out = {};
|
|
5568
|
-
const writer = new BinaryWriter(1024);
|
|
5569
5710
|
for (const reducer of def.reducers) {
|
|
5570
5711
|
const reducerName = reducer.name;
|
|
5712
|
+
const encodedReducerName = this.#reducerNameBytes[reducerName];
|
|
5571
5713
|
const key = reducer.accessorName;
|
|
5572
5714
|
const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
|
|
5573
5715
|
out[key] = (params) => {
|
|
5716
|
+
const writer = this.#reducerArgsEncoder;
|
|
5574
5717
|
writer.clear();
|
|
5575
5718
|
serializeArgs(writer, params);
|
|
5576
5719
|
const argsBuffer = writer.getBuffer();
|
|
5577
|
-
return this
|
|
5720
|
+
return this.#callReducerWithEncodedName(
|
|
5721
|
+
reducerName,
|
|
5722
|
+
encodedReducerName,
|
|
5723
|
+
argsBuffer,
|
|
5724
|
+
params
|
|
5725
|
+
);
|
|
5578
5726
|
};
|
|
5579
5727
|
}
|
|
5580
5728
|
return out;
|
|
@@ -5584,13 +5732,18 @@ var DbConnectionImpl = class {
|
|
|
5584
5732
|
const writer = new BinaryWriter(1024);
|
|
5585
5733
|
for (const procedure of def.procedures) {
|
|
5586
5734
|
const procedureName = procedure.name;
|
|
5735
|
+
const encodedProcedureName = this.#procedureNameBytes[procedureName];
|
|
5587
5736
|
const key = procedure.accessorName;
|
|
5588
5737
|
const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
|
|
5589
5738
|
out[key] = (params) => {
|
|
5590
5739
|
writer.clear();
|
|
5591
5740
|
serializeArgs(writer, params);
|
|
5592
5741
|
const argsBuffer = writer.getBuffer();
|
|
5593
|
-
return this
|
|
5742
|
+
return this.#callProcedureWithEncodedName(
|
|
5743
|
+
procedureName,
|
|
5744
|
+
encodedProcedureName,
|
|
5745
|
+
argsBuffer
|
|
5746
|
+
).then((returnBuf) => {
|
|
5594
5747
|
return deserializeReturn(new BinaryReader(returnBuf));
|
|
5595
5748
|
});
|
|
5596
5749
|
};
|
|
@@ -5602,8 +5755,8 @@ var DbConnectionImpl = class {
|
|
|
5602
5755
|
db: this.db,
|
|
5603
5756
|
reducers: this.reducers,
|
|
5604
5757
|
isActive: this.isActive,
|
|
5605
|
-
subscriptionBuilder: this
|
|
5606
|
-
disconnect: this
|
|
5758
|
+
subscriptionBuilder: this.#boundSubscriptionBuilder,
|
|
5759
|
+
disconnect: this.#boundDisconnect,
|
|
5607
5760
|
event
|
|
5608
5761
|
};
|
|
5609
5762
|
}
|
|
@@ -5648,21 +5801,16 @@ var DbConnectionImpl = class {
|
|
|
5648
5801
|
}
|
|
5649
5802
|
#parseRowList(type, tableName, rowList) {
|
|
5650
5803
|
const buffer = rowList.rowsData;
|
|
5651
|
-
const reader =
|
|
5804
|
+
const reader = this.#rowListReader;
|
|
5805
|
+
reader.reset(buffer);
|
|
5652
5806
|
const rows = [];
|
|
5653
5807
|
const deserializeRow = this.#rowDeserializers[tableName];
|
|
5654
|
-
const
|
|
5655
|
-
const columnsArray = Object.entries(table2.columns);
|
|
5656
|
-
const primaryKeyColumnEntry = columnsArray.find(
|
|
5657
|
-
(col) => col[1].columnMetadata.isPrimaryKey
|
|
5658
|
-
);
|
|
5808
|
+
const { primaryKeyColName, primaryKeyColType } = this.#rowIdMetadata[tableName];
|
|
5659
5809
|
let previousOffset = 0;
|
|
5660
5810
|
while (reader.remaining > 0) {
|
|
5661
5811
|
const row = deserializeRow(reader);
|
|
5662
5812
|
let rowId = void 0;
|
|
5663
|
-
if (
|
|
5664
|
-
const primaryKeyColName = primaryKeyColumnEntry[0];
|
|
5665
|
-
const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType;
|
|
5813
|
+
if (primaryKeyColName !== void 0 && primaryKeyColType !== void 0) {
|
|
5666
5814
|
rowId = AlgebraicType.intoMapKey(
|
|
5667
5815
|
primaryKeyColType,
|
|
5668
5816
|
row[primaryKeyColName]
|
|
@@ -5743,40 +5891,136 @@ var DbConnectionImpl = class {
|
|
|
5743
5891
|
return this.#mergeTableUpdates(updates);
|
|
5744
5892
|
}
|
|
5745
5893
|
#flushOutboundQueue(wsResolved) {
|
|
5894
|
+
if (this.#negotiatedWsProtocol === V3_WS_PROTOCOL) {
|
|
5895
|
+
this.#flushOutboundQueueV3(wsResolved);
|
|
5896
|
+
return;
|
|
5897
|
+
}
|
|
5898
|
+
this.#flushOutboundQueueV2(wsResolved);
|
|
5899
|
+
}
|
|
5900
|
+
#flushOutboundQueueV2(wsResolved) {
|
|
5746
5901
|
const pending = this.#outboundQueue.splice(0);
|
|
5747
5902
|
for (const message of pending) {
|
|
5748
5903
|
wsResolved.send(message);
|
|
5749
5904
|
}
|
|
5750
5905
|
}
|
|
5906
|
+
#flushOutboundQueueV3(wsResolved) {
|
|
5907
|
+
if (this.#outboundQueue.length === 0) {
|
|
5908
|
+
return;
|
|
5909
|
+
}
|
|
5910
|
+
const batchSize = countClientMessagesForV3Frame(
|
|
5911
|
+
this.#outboundQueue,
|
|
5912
|
+
MAX_V3_OUTBOUND_FRAME_BYTES
|
|
5913
|
+
);
|
|
5914
|
+
wsResolved.send(
|
|
5915
|
+
encodeClientMessagesV3(
|
|
5916
|
+
this.#clientFrameEncoder,
|
|
5917
|
+
this.#outboundQueue,
|
|
5918
|
+
batchSize
|
|
5919
|
+
)
|
|
5920
|
+
);
|
|
5921
|
+
if (batchSize === this.#outboundQueue.length) {
|
|
5922
|
+
this.#outboundQueue.length = 0;
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5925
|
+
this.#outboundQueue.copyWithin(0, batchSize);
|
|
5926
|
+
this.#outboundQueue.length -= batchSize;
|
|
5927
|
+
if (this.#outboundQueue.length > 0) {
|
|
5928
|
+
this.#scheduleDeferredOutboundFlush();
|
|
5929
|
+
}
|
|
5930
|
+
}
|
|
5931
|
+
#scheduleOutboundFlush() {
|
|
5932
|
+
this.#scheduleOutboundFlushWith("microtask");
|
|
5933
|
+
}
|
|
5934
|
+
#scheduleDeferredOutboundFlush() {
|
|
5935
|
+
this.#scheduleOutboundFlushWith("next-task");
|
|
5936
|
+
}
|
|
5937
|
+
#scheduleOutboundFlushWith(schedule) {
|
|
5938
|
+
if (this.#isOutboundFlushScheduled) {
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
this.#isOutboundFlushScheduled = true;
|
|
5942
|
+
const flush = () => {
|
|
5943
|
+
this.#isOutboundFlushScheduled = false;
|
|
5944
|
+
if (this.ws && this.isActive) {
|
|
5945
|
+
this.#flushOutboundQueue(this.ws);
|
|
5946
|
+
}
|
|
5947
|
+
};
|
|
5948
|
+
if (schedule === "next-task") {
|
|
5949
|
+
setTimeout(flush, 0);
|
|
5950
|
+
} else {
|
|
5951
|
+
queueMicrotask(flush);
|
|
5952
|
+
}
|
|
5953
|
+
}
|
|
5954
|
+
#reducerArgsEncoder = new BinaryWriter(1024);
|
|
5751
5955
|
#clientMessageEncoder = new BinaryWriter(1024);
|
|
5956
|
+
#sendEncodedMessage(encoded, describe) {
|
|
5957
|
+
stdbLogger("trace", describe);
|
|
5958
|
+
if (this.ws && this.isActive) {
|
|
5959
|
+
if (this.#negotiatedWsProtocol === V2_WS_PROTOCOL) {
|
|
5960
|
+
if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
|
|
5961
|
+
this.ws.send(encoded);
|
|
5962
|
+
return;
|
|
5963
|
+
}
|
|
5964
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5965
|
+
this.#scheduleOutboundFlush();
|
|
5966
|
+
} else {
|
|
5967
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5752
5970
|
#sendMessage(message) {
|
|
5753
5971
|
const writer = this.#clientMessageEncoder;
|
|
5754
5972
|
writer.clear();
|
|
5755
5973
|
ClientMessage.serialize(writer, message);
|
|
5756
5974
|
const encoded = writer.getBuffer();
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5975
|
+
const isLive = !!(this.ws && this.isActive);
|
|
5976
|
+
this.#sendEncodedMessage(
|
|
5977
|
+
encoded,
|
|
5978
|
+
() => isLive ? `Sending message to server: ${stringify(message)}` : `Queuing message to server: ${stringify(message)}`
|
|
5979
|
+
);
|
|
5980
|
+
}
|
|
5981
|
+
#sendCallReducerMessage(requestId, reducerNameBytes, argsBuffer) {
|
|
5982
|
+
const writer = this.#clientMessageEncoder;
|
|
5983
|
+
writer.clear();
|
|
5984
|
+
writer.writeByte(CLIENT_MESSAGE_CALL_REDUCER_TAG);
|
|
5985
|
+
writer.writeU32(requestId);
|
|
5986
|
+
writer.writeU8(0);
|
|
5987
|
+
writer.writeUInt8Array(reducerNameBytes);
|
|
5988
|
+
writer.writeUInt8Array(argsBuffer);
|
|
5989
|
+
const encoded = writer.getBuffer();
|
|
5990
|
+
this.#sendEncodedMessage(
|
|
5991
|
+
encoded,
|
|
5992
|
+
() => `Sending reducer call message to server: requestId=${requestId}`
|
|
5993
|
+
);
|
|
5994
|
+
}
|
|
5995
|
+
#sendCallProcedureMessage(requestId, procedureNameBytes, argsBuffer) {
|
|
5996
|
+
const writer = this.#clientMessageEncoder;
|
|
5997
|
+
writer.clear();
|
|
5998
|
+
writer.writeByte(CLIENT_MESSAGE_CALL_PROCEDURE_TAG);
|
|
5999
|
+
writer.writeU32(requestId);
|
|
6000
|
+
writer.writeU8(0);
|
|
6001
|
+
writer.writeUInt8Array(procedureNameBytes);
|
|
6002
|
+
writer.writeUInt8Array(argsBuffer);
|
|
6003
|
+
const encoded = writer.getBuffer();
|
|
6004
|
+
this.#sendEncodedMessage(
|
|
6005
|
+
encoded,
|
|
6006
|
+
() => `Sending procedure call message to server: requestId=${requestId}`
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
#setConnectionId(connectionId) {
|
|
6010
|
+
this.connectionId = connectionId;
|
|
6011
|
+
this.#connectionIdHex = connectionId.toHexString();
|
|
5771
6012
|
}
|
|
5772
6013
|
#nextEventId() {
|
|
5773
6014
|
this.#eventId += 1;
|
|
5774
|
-
return `${this
|
|
6015
|
+
return `${this.#connectionIdHex}:${this.#eventId}`;
|
|
5775
6016
|
}
|
|
5776
6017
|
/**
|
|
5777
6018
|
* Handles WebSocket onOpen event.
|
|
5778
6019
|
*/
|
|
5779
6020
|
#handleOnOpen() {
|
|
6021
|
+
if (this.ws) {
|
|
6022
|
+
this.#negotiatedWsProtocol = normalizeWsProtocol(this.ws.protocol);
|
|
6023
|
+
}
|
|
5780
6024
|
this.isActive = true;
|
|
5781
6025
|
if (this.ws) {
|
|
5782
6026
|
this.#flushOutboundQueue(this.ws);
|
|
@@ -5811,8 +6055,16 @@ var DbConnectionImpl = class {
|
|
|
5811
6055
|
eventContext
|
|
5812
6056
|
);
|
|
5813
6057
|
}
|
|
5814
|
-
|
|
5815
|
-
|
|
6058
|
+
#dispatchPendingCallbacks(callbacks) {
|
|
6059
|
+
stdbLogger(
|
|
6060
|
+
"trace",
|
|
6061
|
+
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6062
|
+
);
|
|
6063
|
+
for (const callback of callbacks) {
|
|
6064
|
+
callback.cb();
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6067
|
+
#processServerMessage(serverMessage) {
|
|
5816
6068
|
stdbLogger(
|
|
5817
6069
|
"trace",
|
|
5818
6070
|
() => `Processing server message: ${stringify(serverMessage)}`
|
|
@@ -5823,7 +6075,7 @@ var DbConnectionImpl = class {
|
|
|
5823
6075
|
if (!this.token && serverMessage.value.token) {
|
|
5824
6076
|
this.token = serverMessage.value.token;
|
|
5825
6077
|
}
|
|
5826
|
-
this
|
|
6078
|
+
this.#setConnectionId(serverMessage.value.connectionId);
|
|
5827
6079
|
this.#emitter.emit("connect", this, this.identity, this.token);
|
|
5828
6080
|
break;
|
|
5829
6081
|
}
|
|
@@ -5849,13 +6101,7 @@ var DbConnectionImpl = class {
|
|
|
5849
6101
|
const callbacks = this.#applyTableUpdates(tableUpdates, eventContext);
|
|
5850
6102
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
5851
6103
|
subscription.emitter.emit("applied", subscriptionEventContext);
|
|
5852
|
-
|
|
5853
|
-
"trace",
|
|
5854
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5855
|
-
);
|
|
5856
|
-
for (const callback of callbacks) {
|
|
5857
|
-
callback.cb();
|
|
5858
|
-
}
|
|
6104
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5859
6105
|
break;
|
|
5860
6106
|
}
|
|
5861
6107
|
case "UnsubscribeApplied": {
|
|
@@ -5878,13 +6124,7 @@ var DbConnectionImpl = class {
|
|
|
5878
6124
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
5879
6125
|
subscription.emitter.emit("end", subscriptionEventContext);
|
|
5880
6126
|
this.#subscriptionManager.subscriptions.delete(querySetId);
|
|
5881
|
-
|
|
5882
|
-
"trace",
|
|
5883
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5884
|
-
);
|
|
5885
|
-
for (const callback of callbacks) {
|
|
5886
|
-
callback.cb();
|
|
5887
|
-
}
|
|
6127
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5888
6128
|
break;
|
|
5889
6129
|
}
|
|
5890
6130
|
case "SubscriptionError": {
|
|
@@ -5932,13 +6172,7 @@ var DbConnectionImpl = class {
|
|
|
5932
6172
|
eventContext,
|
|
5933
6173
|
serverMessage.value
|
|
5934
6174
|
);
|
|
5935
|
-
|
|
5936
|
-
"trace",
|
|
5937
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5938
|
-
);
|
|
5939
|
-
for (const callback of callbacks) {
|
|
5940
|
-
callback.cb();
|
|
5941
|
-
}
|
|
6175
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5942
6176
|
break;
|
|
5943
6177
|
}
|
|
5944
6178
|
case "ReducerResult": {
|
|
@@ -5966,13 +6200,7 @@ var DbConnectionImpl = class {
|
|
|
5966
6200
|
eventContext,
|
|
5967
6201
|
result.value.transactionUpdate
|
|
5968
6202
|
);
|
|
5969
|
-
|
|
5970
|
-
"trace",
|
|
5971
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5972
|
-
);
|
|
5973
|
-
for (const callback of callbacks) {
|
|
5974
|
-
callback.cb();
|
|
5975
|
-
}
|
|
6203
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5976
6204
|
}
|
|
5977
6205
|
this.#reducerCallInfo.delete(requestId);
|
|
5978
6206
|
const cb = this.#reducerCallbacks.get(requestId);
|
|
@@ -5997,14 +6225,55 @@ var DbConnectionImpl = class {
|
|
|
5997
6225
|
}
|
|
5998
6226
|
}
|
|
5999
6227
|
}
|
|
6228
|
+
#processV2Message(data) {
|
|
6229
|
+
const reader = this.#messageReader;
|
|
6230
|
+
reader.reset(data);
|
|
6231
|
+
this.#processServerMessage(ServerMessage.deserialize(reader));
|
|
6232
|
+
}
|
|
6233
|
+
#processMessage(data) {
|
|
6234
|
+
if (this.#negotiatedWsProtocol !== V3_WS_PROTOCOL) {
|
|
6235
|
+
this.#processV2Message(data);
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
const messageCount = forEachServerMessageV3(
|
|
6239
|
+
this.#messageReader,
|
|
6240
|
+
data,
|
|
6241
|
+
(serverMessage) => {
|
|
6242
|
+
this.#processServerMessage(serverMessage);
|
|
6243
|
+
}
|
|
6244
|
+
);
|
|
6245
|
+
stdbLogger(
|
|
6246
|
+
"trace",
|
|
6247
|
+
() => `Processing server v3 payload with ${messageCount} message(s)`
|
|
6248
|
+
);
|
|
6249
|
+
}
|
|
6000
6250
|
/**
|
|
6001
6251
|
* Handles WebSocket onMessage event.
|
|
6002
6252
|
* @param wsMessage MessageEvent object.
|
|
6003
6253
|
*/
|
|
6004
6254
|
#handleOnMessage(wsMessage) {
|
|
6005
|
-
this.#
|
|
6006
|
-
|
|
6007
|
-
|
|
6255
|
+
this.#inboundQueue.push(wsMessage.data);
|
|
6256
|
+
if (this.#isDrainingInboundQueue) {
|
|
6257
|
+
return;
|
|
6258
|
+
}
|
|
6259
|
+
this.#isDrainingInboundQueue = true;
|
|
6260
|
+
try {
|
|
6261
|
+
while (this.#inboundQueueOffset < this.#inboundQueue.length) {
|
|
6262
|
+
const data = this.#inboundQueue[this.#inboundQueueOffset];
|
|
6263
|
+
this.#inboundQueueOffset += 1;
|
|
6264
|
+
if (data) {
|
|
6265
|
+
this.#processMessage(data);
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
} finally {
|
|
6269
|
+
if (this.#inboundQueueOffset >= this.#inboundQueue.length) {
|
|
6270
|
+
this.#inboundQueue.length = 0;
|
|
6271
|
+
} else if (this.#inboundQueueOffset > 0) {
|
|
6272
|
+
this.#inboundQueue = this.#inboundQueue.slice(this.#inboundQueueOffset);
|
|
6273
|
+
}
|
|
6274
|
+
this.#inboundQueueOffset = 0;
|
|
6275
|
+
this.#isDrainingInboundQueue = false;
|
|
6276
|
+
}
|
|
6008
6277
|
}
|
|
6009
6278
|
/**
|
|
6010
6279
|
* Call a reducer on your SpacetimeDB module.
|
|
@@ -6013,6 +6282,45 @@ var DbConnectionImpl = class {
|
|
|
6013
6282
|
* @param argsSerializer The arguments to pass to the reducer
|
|
6014
6283
|
*/
|
|
6015
6284
|
callReducer(reducerName, argsBuffer, reducerArgs) {
|
|
6285
|
+
const encodedReducerName = this.#reducerNameBytes[reducerName];
|
|
6286
|
+
if (encodedReducerName) {
|
|
6287
|
+
return this.#callReducerWithEncodedName(
|
|
6288
|
+
reducerName,
|
|
6289
|
+
encodedReducerName,
|
|
6290
|
+
argsBuffer,
|
|
6291
|
+
reducerArgs
|
|
6292
|
+
);
|
|
6293
|
+
}
|
|
6294
|
+
return this.#callReducerGeneric(reducerName, argsBuffer, reducerArgs);
|
|
6295
|
+
}
|
|
6296
|
+
#callReducerWithEncodedName(reducerName, encodedReducerName, argsBuffer, reducerArgs) {
|
|
6297
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6298
|
+
const requestId = this.#getNextRequestId();
|
|
6299
|
+
this.#sendCallReducerMessage(requestId, encodedReducerName, argsBuffer);
|
|
6300
|
+
if (reducerArgs) {
|
|
6301
|
+
this.#reducerCallInfo.set(requestId, {
|
|
6302
|
+
name: reducerName,
|
|
6303
|
+
args: reducerArgs
|
|
6304
|
+
});
|
|
6305
|
+
}
|
|
6306
|
+
this.#reducerCallbacks.set(requestId, (result) => {
|
|
6307
|
+
if (result.tag === "Ok" || result.tag === "OkEmpty") {
|
|
6308
|
+
resolve();
|
|
6309
|
+
} else {
|
|
6310
|
+
if (result.tag === "Err") {
|
|
6311
|
+
const reader = new BinaryReader(result.value);
|
|
6312
|
+
const errorString = reader.readString();
|
|
6313
|
+
reject(new SenderError(errorString));
|
|
6314
|
+
} else if (result.tag === "InternalError") {
|
|
6315
|
+
reject(new InternalError(result.value));
|
|
6316
|
+
} else {
|
|
6317
|
+
reject(new Error("Unexpected reducer result"));
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
});
|
|
6321
|
+
return promise;
|
|
6322
|
+
}
|
|
6323
|
+
#callReducerGeneric(reducerName, argsBuffer, reducerArgs) {
|
|
6016
6324
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6017
6325
|
const requestId = this.#getNextRequestId();
|
|
6018
6326
|
const message = ClientMessage.CallReducer({
|
|
@@ -6052,7 +6360,8 @@ var DbConnectionImpl = class {
|
|
|
6052
6360
|
* @param params The arguments to pass to the reducer
|
|
6053
6361
|
*/
|
|
6054
6362
|
callReducerWithParams(reducerName, _paramsType, params) {
|
|
6055
|
-
const writer =
|
|
6363
|
+
const writer = this.#reducerArgsEncoder;
|
|
6364
|
+
writer.clear();
|
|
6056
6365
|
this.#reducerArgsSerializers[reducerName].serialize(writer, params);
|
|
6057
6366
|
const argsBuffer = writer.getBuffer();
|
|
6058
6367
|
return this.callReducer(reducerName, argsBuffer, params);
|
|
@@ -6064,6 +6373,30 @@ var DbConnectionImpl = class {
|
|
|
6064
6373
|
* @param argsBuffer The arguments to pass to the reducer
|
|
6065
6374
|
*/
|
|
6066
6375
|
callProcedure(procedureName, argsBuffer) {
|
|
6376
|
+
const encodedProcedureName = this.#procedureNameBytes[procedureName];
|
|
6377
|
+
if (encodedProcedureName) {
|
|
6378
|
+
return this.#callProcedureWithEncodedName(
|
|
6379
|
+
procedureName,
|
|
6380
|
+
encodedProcedureName,
|
|
6381
|
+
argsBuffer
|
|
6382
|
+
);
|
|
6383
|
+
}
|
|
6384
|
+
return this.#callProcedureGeneric(procedureName, argsBuffer);
|
|
6385
|
+
}
|
|
6386
|
+
#callProcedureWithEncodedName(procedureName, encodedProcedureName, argsBuffer) {
|
|
6387
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6388
|
+
const requestId = this.#getNextRequestId();
|
|
6389
|
+
this.#sendCallProcedureMessage(requestId, encodedProcedureName, argsBuffer);
|
|
6390
|
+
this.#procedureCallbacks.set(requestId, (result) => {
|
|
6391
|
+
if (result.tag === "Ok") {
|
|
6392
|
+
resolve(result.value);
|
|
6393
|
+
} else {
|
|
6394
|
+
reject(result.value);
|
|
6395
|
+
}
|
|
6396
|
+
});
|
|
6397
|
+
return promise;
|
|
6398
|
+
}
|
|
6399
|
+
#callProcedureGeneric(procedureName, argsBuffer) {
|
|
6067
6400
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6068
6401
|
const requestId = this.#getNextRequestId();
|
|
6069
6402
|
const message = ClientMessage.CallProcedure({
|
|
@@ -7004,7 +7337,7 @@ function table(opts, row, ..._) {
|
|
|
7004
7337
|
increment: 1n
|
|
7005
7338
|
});
|
|
7006
7339
|
}
|
|
7007
|
-
if (meta
|
|
7340
|
+
if (Object.prototype.hasOwnProperty.call(meta, "defaultValue")) {
|
|
7008
7341
|
const writer = new BinaryWriter(16);
|
|
7009
7342
|
builder.serialize(writer, meta.defaultValue);
|
|
7010
7343
|
defaultValues.push({
|