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