spacetimedb 2.1.0 → 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 +7 -2
- package/dist/angular/index.cjs.map +1 -1
- package/dist/angular/index.mjs +7 -2
- package/dist/angular/index.mjs.map +1 -1
- package/dist/browser/angular/index.mjs +7 -2
- package/dist/browser/angular/index.mjs.map +1 -1
- package/dist/browser/react/index.mjs +57 -6
- package/dist/browser/react/index.mjs.map +1 -1
- package/dist/browser/svelte/index.mjs +7 -2
- package/dist/browser/svelte/index.mjs.map +1 -1
- package/dist/browser/vue/index.mjs +7 -2
- package/dist/browser/vue/index.mjs.map +1 -1
- package/dist/index.browser.mjs +459 -138
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +459 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +459 -138
- package/dist/index.mjs.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/table.d.ts +6 -0
- 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 +57 -5
- 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 +57 -6
- 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 +459 -138
- package/dist/sdk/index.browser.mjs.map +1 -1
- package/dist/sdk/index.cjs +459 -138
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.mjs +459 -138
- 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 +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.mjs +53 -6
- 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 +7 -2
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.mjs +7 -2
- package/dist/svelte/index.mjs.map +1 -1
- package/dist/tanstack/index.cjs +7 -2
- package/dist/tanstack/index.cjs.map +1 -1
- package/dist/tanstack/index.mjs +7 -2
- package/dist/tanstack/index.mjs.map +1 -1
- package/dist/vue/index.cjs +7 -2
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.mjs +7 -2
- package/dist/vue/index.mjs.map +1 -1
- package/package.json +2 -2
- 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/table.ts +9 -1
- package/src/react/index.ts +1 -0
- package/src/react/useProcedure.ts +60 -0
- package/src/react/useTable.ts +17 -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 +1 -1
- package/src/server/runtime.ts +39 -1
- package/src/server/sys.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);
|
|
@@ -4467,6 +4472,7 @@ var scalarCompare = (x, y) => {
|
|
|
4467
4472
|
return x < y ? -1 : 1;
|
|
4468
4473
|
};
|
|
4469
4474
|
var TableCacheImpl = class {
|
|
4475
|
+
hasPrimaryKey;
|
|
4470
4476
|
rows;
|
|
4471
4477
|
tableDef;
|
|
4472
4478
|
emitter;
|
|
@@ -4480,6 +4486,9 @@ var TableCacheImpl = class {
|
|
|
4480
4486
|
this.tableDef = tableDef;
|
|
4481
4487
|
this.rows = /* @__PURE__ */ new Map();
|
|
4482
4488
|
this.emitter = new EventEmitter();
|
|
4489
|
+
this.hasPrimaryKey = Object.values(this.tableDef.columns).some(
|
|
4490
|
+
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4491
|
+
);
|
|
4483
4492
|
for (const idxDef of this.tableDef.resolvedIndexes) {
|
|
4484
4493
|
const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
|
|
4485
4494
|
this[idxDef.name] = index;
|
|
@@ -4589,10 +4598,7 @@ var TableCacheImpl = class {
|
|
|
4589
4598
|
}
|
|
4590
4599
|
return pendingCallbacks;
|
|
4591
4600
|
}
|
|
4592
|
-
|
|
4593
|
-
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4594
|
-
);
|
|
4595
|
-
if (hasPrimaryKey) {
|
|
4601
|
+
if (this.hasPrimaryKey) {
|
|
4596
4602
|
const insertMap = /* @__PURE__ */ new Map();
|
|
4597
4603
|
const deleteMap = /* @__PURE__ */ new Map();
|
|
4598
4604
|
for (const op of operations) {
|
|
@@ -5000,27 +5006,17 @@ async function decompress(buffer, type, chunkSize = 128 * 1024) {
|
|
|
5000
5006
|
});
|
|
5001
5007
|
const decompressionStream = new DecompressionStream(type);
|
|
5002
5008
|
const decompressedStream = readableStream.pipeThrough(decompressionStream);
|
|
5003
|
-
const reader = decompressedStream.getReader();
|
|
5004
5009
|
const chunks = [];
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
totalLength += result.value.length;
|
|
5010
|
-
}
|
|
5011
|
-
const decompressedArray = new Uint8Array(totalLength);
|
|
5012
|
-
let chunkOffset = 0;
|
|
5013
|
-
for (const chunk of chunks) {
|
|
5014
|
-
decompressedArray.set(chunk, chunkOffset);
|
|
5015
|
-
chunkOffset += chunk.length;
|
|
5016
|
-
}
|
|
5017
|
-
return decompressedArray;
|
|
5010
|
+
for await (const chunk of decompressedStream) {
|
|
5011
|
+
chunks.push(chunk);
|
|
5012
|
+
}
|
|
5013
|
+
return new Blob(chunks).bytes();
|
|
5018
5014
|
}
|
|
5019
5015
|
|
|
5020
5016
|
// src/sdk/ws.ts
|
|
5021
5017
|
async function resolveWS() {
|
|
5022
|
-
if (typeof
|
|
5023
|
-
return
|
|
5018
|
+
if (typeof WebSocket !== "undefined") {
|
|
5019
|
+
return WebSocket;
|
|
5024
5020
|
}
|
|
5025
5021
|
const dynamicImport = new Function("m", "return import(m)");
|
|
5026
5022
|
try {
|
|
@@ -5034,9 +5030,54 @@ async function resolveWS() {
|
|
|
5034
5030
|
throw err;
|
|
5035
5031
|
}
|
|
5036
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
|
+
}
|
|
5037
5075
|
|
|
5038
5076
|
// src/sdk/websocket_decompress_adapter.ts
|
|
5039
5077
|
var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
5078
|
+
get protocol() {
|
|
5079
|
+
return this.#ws.protocol;
|
|
5080
|
+
}
|
|
5040
5081
|
set onclose(handler) {
|
|
5041
5082
|
this.#ws.onclose = handler;
|
|
5042
5083
|
}
|
|
@@ -5060,9 +5101,7 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
5060
5101
|
case 0:
|
|
5061
5102
|
return data;
|
|
5062
5103
|
case 1:
|
|
5063
|
-
|
|
5064
|
-
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
5065
|
-
);
|
|
5104
|
+
return await decompress(data, "brotli");
|
|
5066
5105
|
case 2:
|
|
5067
5106
|
return await decompress(data, "gzip");
|
|
5068
5107
|
default:
|
|
@@ -5078,51 +5117,10 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
5078
5117
|
this.#ws.close();
|
|
5079
5118
|
}
|
|
5080
5119
|
constructor(ws) {
|
|
5081
|
-
ws.binaryType = "arraybuffer";
|
|
5082
5120
|
this.#ws = ws;
|
|
5083
5121
|
}
|
|
5084
|
-
static async
|
|
5085
|
-
|
|
5086
|
-
nameOrAddress,
|
|
5087
|
-
wsProtocol,
|
|
5088
|
-
authToken,
|
|
5089
|
-
compression,
|
|
5090
|
-
lightMode,
|
|
5091
|
-
confirmedReads
|
|
5092
|
-
}) {
|
|
5093
|
-
const headers = new Headers();
|
|
5094
|
-
const WS = await resolveWS();
|
|
5095
|
-
let temporaryAuthToken = void 0;
|
|
5096
|
-
if (authToken) {
|
|
5097
|
-
headers.set("Authorization", `Bearer ${authToken}`);
|
|
5098
|
-
const tokenUrl = new URL("v1/identity/websocket-token", url);
|
|
5099
|
-
tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
5100
|
-
const response = await fetch(tokenUrl, { method: "POST", headers });
|
|
5101
|
-
if (response.ok) {
|
|
5102
|
-
const { token } = await response.json();
|
|
5103
|
-
temporaryAuthToken = token;
|
|
5104
|
-
} else {
|
|
5105
|
-
return Promise.reject(
|
|
5106
|
-
new Error(`Failed to verify token: ${response.statusText}`)
|
|
5107
|
-
);
|
|
5108
|
-
}
|
|
5109
|
-
}
|
|
5110
|
-
const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
|
|
5111
|
-
if (temporaryAuthToken) {
|
|
5112
|
-
databaseUrl.searchParams.set("token", temporaryAuthToken);
|
|
5113
|
-
}
|
|
5114
|
-
databaseUrl.searchParams.set(
|
|
5115
|
-
"compression",
|
|
5116
|
-
compression === "gzip" ? "Gzip" : "None"
|
|
5117
|
-
);
|
|
5118
|
-
if (lightMode) {
|
|
5119
|
-
databaseUrl.searchParams.set("light", "true");
|
|
5120
|
-
}
|
|
5121
|
-
if (confirmedReads !== void 0) {
|
|
5122
|
-
databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
|
|
5123
|
-
}
|
|
5124
|
-
const ws = new WS(databaseUrl.toString(), wsProtocol);
|
|
5125
|
-
return new _WebsocketDecompressAdapter(ws);
|
|
5122
|
+
static async openWebSocket(args) {
|
|
5123
|
+
return new _WebsocketDecompressAdapter(await openWebSocket(args));
|
|
5126
5124
|
}
|
|
5127
5125
|
};
|
|
5128
5126
|
|
|
@@ -5139,7 +5137,7 @@ var DbConnectionBuilder = class {
|
|
|
5139
5137
|
constructor(remoteModule, dbConnectionCtor) {
|
|
5140
5138
|
this.remoteModule = remoteModule;
|
|
5141
5139
|
this.dbConnectionCtor = dbConnectionCtor;
|
|
5142
|
-
this.#createWSFn = WebsocketDecompressAdapter.
|
|
5140
|
+
this.#createWSFn = WebsocketDecompressAdapter.openWebSocket;
|
|
5143
5141
|
}
|
|
5144
5142
|
#uri;
|
|
5145
5143
|
#nameOrAddress;
|
|
@@ -5194,6 +5192,16 @@ var DbConnectionBuilder = class {
|
|
|
5194
5192
|
* @param compression The compression algorithm to use for the connection.
|
|
5195
5193
|
*/
|
|
5196
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
|
+
}
|
|
5197
5205
|
this.#compression = compression;
|
|
5198
5206
|
return this;
|
|
5199
5207
|
}
|
|
@@ -5557,6 +5565,100 @@ var SubscriptionHandleImpl = class {
|
|
|
5557
5565
|
return this.#activeState;
|
|
5558
5566
|
}
|
|
5559
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;
|
|
5560
5662
|
var DbConnectionImpl = class {
|
|
5561
5663
|
/**
|
|
5562
5664
|
* Whether or not the connection is active.
|
|
@@ -5591,22 +5693,35 @@ var DbConnectionImpl = class {
|
|
|
5591
5693
|
* The `ConnectionId` of the connection to to the database.
|
|
5592
5694
|
*/
|
|
5593
5695
|
connectionId = ConnectionId.random();
|
|
5696
|
+
#connectionIdHex = this.connectionId.toHexString();
|
|
5594
5697
|
// These fields are meant to be strictly private.
|
|
5595
5698
|
#queryId = 0;
|
|
5596
5699
|
#requestId = 0;
|
|
5597
5700
|
#eventId = 0;
|
|
5598
5701
|
#emitter;
|
|
5599
|
-
#
|
|
5702
|
+
#inboundQueue = [];
|
|
5703
|
+
#inboundQueueOffset = 0;
|
|
5704
|
+
#isDrainingInboundQueue = false;
|
|
5600
5705
|
#outboundQueue = [];
|
|
5706
|
+
#isOutboundFlushScheduled = false;
|
|
5707
|
+
#negotiatedWsProtocol = V2_WS_PROTOCOL;
|
|
5601
5708
|
#subscriptionManager = new SubscriptionManager();
|
|
5602
5709
|
#remoteModule;
|
|
5603
5710
|
#reducerCallbacks = /* @__PURE__ */ new Map();
|
|
5604
5711
|
#reducerCallInfo = /* @__PURE__ */ new Map();
|
|
5605
5712
|
#procedureCallbacks = /* @__PURE__ */ new Map();
|
|
5606
5713
|
#rowDeserializers;
|
|
5714
|
+
#rowIdMetadata;
|
|
5607
5715
|
#reducerArgsSerializers;
|
|
5608
5716
|
#procedureSerializers;
|
|
5717
|
+
#reducerNameBytes;
|
|
5718
|
+
#procedureNameBytes;
|
|
5609
5719
|
#sourceNameToTableDef;
|
|
5720
|
+
#messageReader = new BinaryReader(new Uint8Array());
|
|
5721
|
+
#rowListReader = new BinaryReader(new Uint8Array());
|
|
5722
|
+
#clientFrameEncoder = new BinaryWriter(1024);
|
|
5723
|
+
#boundSubscriptionBuilder;
|
|
5724
|
+
#boundDisconnect;
|
|
5610
5725
|
// These fields are not part of the public API, but in a pinch you
|
|
5611
5726
|
// could use JavaScript to access them by bypassing TypeScript's
|
|
5612
5727
|
// private fields.
|
|
@@ -5635,22 +5750,35 @@ var DbConnectionImpl = class {
|
|
|
5635
5750
|
this.token = token;
|
|
5636
5751
|
this.#remoteModule = remoteModule;
|
|
5637
5752
|
this.#emitter = emitter;
|
|
5753
|
+
this.#boundSubscriptionBuilder = this.subscriptionBuilder.bind(this);
|
|
5754
|
+
this.#boundDisconnect = this.disconnect.bind(this);
|
|
5638
5755
|
this.#rowDeserializers = /* @__PURE__ */ Object.create(null);
|
|
5756
|
+
this.#rowIdMetadata = /* @__PURE__ */ Object.create(null);
|
|
5639
5757
|
this.#sourceNameToTableDef = /* @__PURE__ */ Object.create(null);
|
|
5640
5758
|
for (const table2 of Object.values(remoteModule.tables)) {
|
|
5641
5759
|
this.#rowDeserializers[table2.sourceName] = ProductType.makeDeserializer(
|
|
5642
5760
|
table2.rowType
|
|
5643
5761
|
);
|
|
5644
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
|
+
} : {};
|
|
5645
5770
|
}
|
|
5646
5771
|
this.#reducerArgsSerializers = /* @__PURE__ */ Object.create(null);
|
|
5772
|
+
this.#reducerNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5647
5773
|
for (const reducer of remoteModule.reducers) {
|
|
5648
5774
|
this.#reducerArgsSerializers[reducer.name] = {
|
|
5649
5775
|
serialize: ProductType.makeSerializer(reducer.paramsType),
|
|
5650
5776
|
deserialize: ProductType.makeDeserializer(reducer.paramsType)
|
|
5651
5777
|
};
|
|
5778
|
+
this.#reducerNameBytes[reducer.name] = TEXT_ENCODER.encode(reducer.name);
|
|
5652
5779
|
}
|
|
5653
5780
|
this.#procedureSerializers = /* @__PURE__ */ Object.create(null);
|
|
5781
|
+
this.#procedureNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5654
5782
|
for (const procedure of remoteModule.procedures) {
|
|
5655
5783
|
this.#procedureSerializers[procedure.name] = {
|
|
5656
5784
|
serializeArgs: ProductType.makeSerializer(
|
|
@@ -5660,9 +5788,11 @@ var DbConnectionImpl = class {
|
|
|
5660
5788
|
procedure.returnType.algebraicType
|
|
5661
5789
|
)
|
|
5662
5790
|
};
|
|
5791
|
+
this.#procedureNameBytes[procedure.name] = TEXT_ENCODER.encode(
|
|
5792
|
+
procedure.name
|
|
5793
|
+
);
|
|
5663
5794
|
}
|
|
5664
|
-
|
|
5665
|
-
url.searchParams.set("connection_id", connectionId);
|
|
5795
|
+
url.searchParams.set("connection_id", this.#connectionIdHex);
|
|
5666
5796
|
this.clientCache = new ClientCache();
|
|
5667
5797
|
this.db = this.#makeDbView();
|
|
5668
5798
|
this.reducers = this.#makeReducers(remoteModule);
|
|
@@ -5670,7 +5800,7 @@ var DbConnectionImpl = class {
|
|
|
5670
5800
|
this.wsPromise = createWSFn({
|
|
5671
5801
|
url,
|
|
5672
5802
|
nameOrAddress,
|
|
5673
|
-
wsProtocol:
|
|
5803
|
+
wsProtocol: [...PREFERRED_WS_PROTOCOLS],
|
|
5674
5804
|
authToken: token,
|
|
5675
5805
|
compression,
|
|
5676
5806
|
lightMode,
|
|
@@ -5714,16 +5844,22 @@ var DbConnectionImpl = class {
|
|
|
5714
5844
|
}
|
|
5715
5845
|
#makeReducers(def) {
|
|
5716
5846
|
const out = {};
|
|
5717
|
-
const writer = new BinaryWriter(1024);
|
|
5718
5847
|
for (const reducer of def.reducers) {
|
|
5719
5848
|
const reducerName = reducer.name;
|
|
5849
|
+
const encodedReducerName = this.#reducerNameBytes[reducerName];
|
|
5720
5850
|
const key = reducer.accessorName;
|
|
5721
5851
|
const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
|
|
5722
5852
|
out[key] = (params) => {
|
|
5853
|
+
const writer = this.#reducerArgsEncoder;
|
|
5723
5854
|
writer.clear();
|
|
5724
5855
|
serializeArgs(writer, params);
|
|
5725
5856
|
const argsBuffer = writer.getBuffer();
|
|
5726
|
-
return this
|
|
5857
|
+
return this.#callReducerWithEncodedName(
|
|
5858
|
+
reducerName,
|
|
5859
|
+
encodedReducerName,
|
|
5860
|
+
argsBuffer,
|
|
5861
|
+
params
|
|
5862
|
+
);
|
|
5727
5863
|
};
|
|
5728
5864
|
}
|
|
5729
5865
|
return out;
|
|
@@ -5733,13 +5869,18 @@ var DbConnectionImpl = class {
|
|
|
5733
5869
|
const writer = new BinaryWriter(1024);
|
|
5734
5870
|
for (const procedure of def.procedures) {
|
|
5735
5871
|
const procedureName = procedure.name;
|
|
5872
|
+
const encodedProcedureName = this.#procedureNameBytes[procedureName];
|
|
5736
5873
|
const key = procedure.accessorName;
|
|
5737
5874
|
const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
|
|
5738
5875
|
out[key] = (params) => {
|
|
5739
5876
|
writer.clear();
|
|
5740
5877
|
serializeArgs(writer, params);
|
|
5741
5878
|
const argsBuffer = writer.getBuffer();
|
|
5742
|
-
return this
|
|
5879
|
+
return this.#callProcedureWithEncodedName(
|
|
5880
|
+
procedureName,
|
|
5881
|
+
encodedProcedureName,
|
|
5882
|
+
argsBuffer
|
|
5883
|
+
).then((returnBuf) => {
|
|
5743
5884
|
return deserializeReturn(new BinaryReader(returnBuf));
|
|
5744
5885
|
});
|
|
5745
5886
|
};
|
|
@@ -5751,8 +5892,8 @@ var DbConnectionImpl = class {
|
|
|
5751
5892
|
db: this.db,
|
|
5752
5893
|
reducers: this.reducers,
|
|
5753
5894
|
isActive: this.isActive,
|
|
5754
|
-
subscriptionBuilder: this
|
|
5755
|
-
disconnect: this
|
|
5895
|
+
subscriptionBuilder: this.#boundSubscriptionBuilder,
|
|
5896
|
+
disconnect: this.#boundDisconnect,
|
|
5756
5897
|
event
|
|
5757
5898
|
};
|
|
5758
5899
|
}
|
|
@@ -5797,21 +5938,16 @@ var DbConnectionImpl = class {
|
|
|
5797
5938
|
}
|
|
5798
5939
|
#parseRowList(type, tableName, rowList) {
|
|
5799
5940
|
const buffer = rowList.rowsData;
|
|
5800
|
-
const reader =
|
|
5941
|
+
const reader = this.#rowListReader;
|
|
5942
|
+
reader.reset(buffer);
|
|
5801
5943
|
const rows = [];
|
|
5802
5944
|
const deserializeRow = this.#rowDeserializers[tableName];
|
|
5803
|
-
const
|
|
5804
|
-
const columnsArray = Object.entries(table2.columns);
|
|
5805
|
-
const primaryKeyColumnEntry = columnsArray.find(
|
|
5806
|
-
(col) => col[1].columnMetadata.isPrimaryKey
|
|
5807
|
-
);
|
|
5945
|
+
const { primaryKeyColName, primaryKeyColType } = this.#rowIdMetadata[tableName];
|
|
5808
5946
|
let previousOffset = 0;
|
|
5809
5947
|
while (reader.remaining > 0) {
|
|
5810
5948
|
const row = deserializeRow(reader);
|
|
5811
5949
|
let rowId = void 0;
|
|
5812
|
-
if (
|
|
5813
|
-
const primaryKeyColName = primaryKeyColumnEntry[0];
|
|
5814
|
-
const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType;
|
|
5950
|
+
if (primaryKeyColName !== void 0 && primaryKeyColType !== void 0) {
|
|
5815
5951
|
rowId = AlgebraicType.intoMapKey(
|
|
5816
5952
|
primaryKeyColType,
|
|
5817
5953
|
row[primaryKeyColName]
|
|
@@ -5892,40 +6028,136 @@ var DbConnectionImpl = class {
|
|
|
5892
6028
|
return this.#mergeTableUpdates(updates);
|
|
5893
6029
|
}
|
|
5894
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) {
|
|
5895
6038
|
const pending = this.#outboundQueue.splice(0);
|
|
5896
6039
|
for (const message of pending) {
|
|
5897
6040
|
wsResolved.send(message);
|
|
5898
6041
|
}
|
|
5899
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);
|
|
5900
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
|
+
}
|
|
5901
6107
|
#sendMessage(message) {
|
|
5902
6108
|
const writer = this.#clientMessageEncoder;
|
|
5903
6109
|
writer.clear();
|
|
5904
6110
|
ClientMessage.serialize(writer, message);
|
|
5905
6111
|
const encoded = writer.getBuffer();
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
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();
|
|
5920
6149
|
}
|
|
5921
6150
|
#nextEventId() {
|
|
5922
6151
|
this.#eventId += 1;
|
|
5923
|
-
return `${this
|
|
6152
|
+
return `${this.#connectionIdHex}:${this.#eventId}`;
|
|
5924
6153
|
}
|
|
5925
6154
|
/**
|
|
5926
6155
|
* Handles WebSocket onOpen event.
|
|
5927
6156
|
*/
|
|
5928
6157
|
#handleOnOpen() {
|
|
6158
|
+
if (this.ws) {
|
|
6159
|
+
this.#negotiatedWsProtocol = normalizeWsProtocol(this.ws.protocol);
|
|
6160
|
+
}
|
|
5929
6161
|
this.isActive = true;
|
|
5930
6162
|
if (this.ws) {
|
|
5931
6163
|
this.#flushOutboundQueue(this.ws);
|
|
@@ -5960,8 +6192,16 @@ var DbConnectionImpl = class {
|
|
|
5960
6192
|
eventContext
|
|
5961
6193
|
);
|
|
5962
6194
|
}
|
|
5963
|
-
|
|
5964
|
-
|
|
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) {
|
|
5965
6205
|
stdbLogger(
|
|
5966
6206
|
"trace",
|
|
5967
6207
|
() => `Processing server message: ${stringify(serverMessage)}`
|
|
@@ -5972,7 +6212,7 @@ var DbConnectionImpl = class {
|
|
|
5972
6212
|
if (!this.token && serverMessage.value.token) {
|
|
5973
6213
|
this.token = serverMessage.value.token;
|
|
5974
6214
|
}
|
|
5975
|
-
this
|
|
6215
|
+
this.#setConnectionId(serverMessage.value.connectionId);
|
|
5976
6216
|
this.#emitter.emit("connect", this, this.identity, this.token);
|
|
5977
6217
|
break;
|
|
5978
6218
|
}
|
|
@@ -5998,13 +6238,7 @@ var DbConnectionImpl = class {
|
|
|
5998
6238
|
const callbacks = this.#applyTableUpdates(tableUpdates, eventContext);
|
|
5999
6239
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
6000
6240
|
subscription.emitter.emit("applied", subscriptionEventContext);
|
|
6001
|
-
|
|
6002
|
-
"trace",
|
|
6003
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6004
|
-
);
|
|
6005
|
-
for (const callback of callbacks) {
|
|
6006
|
-
callback.cb();
|
|
6007
|
-
}
|
|
6241
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
6008
6242
|
break;
|
|
6009
6243
|
}
|
|
6010
6244
|
case "UnsubscribeApplied": {
|
|
@@ -6027,13 +6261,7 @@ var DbConnectionImpl = class {
|
|
|
6027
6261
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
6028
6262
|
subscription.emitter.emit("end", subscriptionEventContext);
|
|
6029
6263
|
this.#subscriptionManager.subscriptions.delete(querySetId);
|
|
6030
|
-
|
|
6031
|
-
"trace",
|
|
6032
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6033
|
-
);
|
|
6034
|
-
for (const callback of callbacks) {
|
|
6035
|
-
callback.cb();
|
|
6036
|
-
}
|
|
6264
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
6037
6265
|
break;
|
|
6038
6266
|
}
|
|
6039
6267
|
case "SubscriptionError": {
|
|
@@ -6081,13 +6309,7 @@ var DbConnectionImpl = class {
|
|
|
6081
6309
|
eventContext,
|
|
6082
6310
|
serverMessage.value
|
|
6083
6311
|
);
|
|
6084
|
-
|
|
6085
|
-
"trace",
|
|
6086
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6087
|
-
);
|
|
6088
|
-
for (const callback of callbacks) {
|
|
6089
|
-
callback.cb();
|
|
6090
|
-
}
|
|
6312
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
6091
6313
|
break;
|
|
6092
6314
|
}
|
|
6093
6315
|
case "ReducerResult": {
|
|
@@ -6115,13 +6337,7 @@ var DbConnectionImpl = class {
|
|
|
6115
6337
|
eventContext,
|
|
6116
6338
|
result.value.transactionUpdate
|
|
6117
6339
|
);
|
|
6118
|
-
|
|
6119
|
-
"trace",
|
|
6120
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6121
|
-
);
|
|
6122
|
-
for (const callback of callbacks) {
|
|
6123
|
-
callback.cb();
|
|
6124
|
-
}
|
|
6340
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
6125
6341
|
}
|
|
6126
6342
|
this.#reducerCallInfo.delete(requestId);
|
|
6127
6343
|
const cb = this.#reducerCallbacks.get(requestId);
|
|
@@ -6146,14 +6362,55 @@ var DbConnectionImpl = class {
|
|
|
6146
6362
|
}
|
|
6147
6363
|
}
|
|
6148
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
|
+
}
|
|
6149
6387
|
/**
|
|
6150
6388
|
* Handles WebSocket onMessage event.
|
|
6151
6389
|
* @param wsMessage MessageEvent object.
|
|
6152
6390
|
*/
|
|
6153
6391
|
#handleOnMessage(wsMessage) {
|
|
6154
|
-
this.#
|
|
6155
|
-
|
|
6156
|
-
|
|
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
|
+
}
|
|
6157
6414
|
}
|
|
6158
6415
|
/**
|
|
6159
6416
|
* Call a reducer on your SpacetimeDB module.
|
|
@@ -6162,6 +6419,45 @@ var DbConnectionImpl = class {
|
|
|
6162
6419
|
* @param argsSerializer The arguments to pass to the reducer
|
|
6163
6420
|
*/
|
|
6164
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) {
|
|
6165
6461
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6166
6462
|
const requestId = this.#getNextRequestId();
|
|
6167
6463
|
const message = ClientMessage.CallReducer({
|
|
@@ -6201,7 +6497,8 @@ var DbConnectionImpl = class {
|
|
|
6201
6497
|
* @param params The arguments to pass to the reducer
|
|
6202
6498
|
*/
|
|
6203
6499
|
callReducerWithParams(reducerName, _paramsType, params) {
|
|
6204
|
-
const writer =
|
|
6500
|
+
const writer = this.#reducerArgsEncoder;
|
|
6501
|
+
writer.clear();
|
|
6205
6502
|
this.#reducerArgsSerializers[reducerName].serialize(writer, params);
|
|
6206
6503
|
const argsBuffer = writer.getBuffer();
|
|
6207
6504
|
return this.callReducer(reducerName, argsBuffer, params);
|
|
@@ -6213,6 +6510,30 @@ var DbConnectionImpl = class {
|
|
|
6213
6510
|
* @param argsBuffer The arguments to pass to the reducer
|
|
6214
6511
|
*/
|
|
6215
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) {
|
|
6216
6537
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6217
6538
|
const requestId = this.#getNextRequestId();
|
|
6218
6539
|
const message = ClientMessage.CallProcedure({
|
|
@@ -7153,7 +7474,7 @@ function table(opts, row, ..._) {
|
|
|
7153
7474
|
increment: 1n
|
|
7154
7475
|
});
|
|
7155
7476
|
}
|
|
7156
|
-
if (meta
|
|
7477
|
+
if (Object.prototype.hasOwnProperty.call(meta, "defaultValue")) {
|
|
7157
7478
|
const writer = new BinaryWriter(16);
|
|
7158
7479
|
builder.serialize(writer, meta.defaultValue);
|
|
7159
7480
|
defaultValues.push({
|