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