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