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/sdk/index.mjs
CHANGED
|
@@ -428,8 +428,8 @@ var BinaryReader = class {
|
|
|
428
428
|
this.view = input instanceof DataView ? input : new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
429
429
|
this.offset = 0;
|
|
430
430
|
}
|
|
431
|
-
reset(
|
|
432
|
-
this.view =
|
|
431
|
+
reset(input) {
|
|
432
|
+
this.view = input instanceof DataView ? input : new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
433
433
|
this.offset = 0;
|
|
434
434
|
}
|
|
435
435
|
get remaining() {
|
|
@@ -621,6 +621,11 @@ var BinaryWriter = class {
|
|
|
621
621
|
this.view.setUint8(this.offset, value);
|
|
622
622
|
this.offset += 1;
|
|
623
623
|
}
|
|
624
|
+
writeBytes(value) {
|
|
625
|
+
this.expandBuffer(value.length);
|
|
626
|
+
new Uint8Array(this.buffer.buffer, this.offset, value.length).set(value);
|
|
627
|
+
this.offset += value.length;
|
|
628
|
+
}
|
|
624
629
|
writeI8(value) {
|
|
625
630
|
this.expandBuffer(1);
|
|
626
631
|
this.view.setInt8(this.offset, value);
|
|
@@ -4330,6 +4335,7 @@ var scalarCompare = (x, y) => {
|
|
|
4330
4335
|
return x < y ? -1 : 1;
|
|
4331
4336
|
};
|
|
4332
4337
|
var TableCacheImpl = class {
|
|
4338
|
+
hasPrimaryKey;
|
|
4333
4339
|
rows;
|
|
4334
4340
|
tableDef;
|
|
4335
4341
|
emitter;
|
|
@@ -4343,6 +4349,9 @@ var TableCacheImpl = class {
|
|
|
4343
4349
|
this.tableDef = tableDef;
|
|
4344
4350
|
this.rows = /* @__PURE__ */ new Map();
|
|
4345
4351
|
this.emitter = new EventEmitter();
|
|
4352
|
+
this.hasPrimaryKey = Object.values(this.tableDef.columns).some(
|
|
4353
|
+
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4354
|
+
);
|
|
4346
4355
|
for (const idxDef of this.tableDef.resolvedIndexes) {
|
|
4347
4356
|
const index = this.#makeReadonlyIndex(this.tableDef, idxDef);
|
|
4348
4357
|
this[idxDef.name] = index;
|
|
@@ -4452,10 +4461,7 @@ var TableCacheImpl = class {
|
|
|
4452
4461
|
}
|
|
4453
4462
|
return pendingCallbacks;
|
|
4454
4463
|
}
|
|
4455
|
-
|
|
4456
|
-
(col) => col.columnMetadata.isPrimaryKey === true
|
|
4457
|
-
);
|
|
4458
|
-
if (hasPrimaryKey) {
|
|
4464
|
+
if (this.hasPrimaryKey) {
|
|
4459
4465
|
const insertMap = /* @__PURE__ */ new Map();
|
|
4460
4466
|
const deleteMap = /* @__PURE__ */ new Map();
|
|
4461
4467
|
for (const op of operations) {
|
|
@@ -4863,27 +4869,17 @@ async function decompress(buffer, type, chunkSize = 128 * 1024) {
|
|
|
4863
4869
|
});
|
|
4864
4870
|
const decompressionStream = new DecompressionStream(type);
|
|
4865
4871
|
const decompressedStream = readableStream.pipeThrough(decompressionStream);
|
|
4866
|
-
const reader = decompressedStream.getReader();
|
|
4867
4872
|
const chunks = [];
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
totalLength += result.value.length;
|
|
4873
|
-
}
|
|
4874
|
-
const decompressedArray = new Uint8Array(totalLength);
|
|
4875
|
-
let chunkOffset = 0;
|
|
4876
|
-
for (const chunk of chunks) {
|
|
4877
|
-
decompressedArray.set(chunk, chunkOffset);
|
|
4878
|
-
chunkOffset += chunk.length;
|
|
4879
|
-
}
|
|
4880
|
-
return decompressedArray;
|
|
4873
|
+
for await (const chunk of decompressedStream) {
|
|
4874
|
+
chunks.push(chunk);
|
|
4875
|
+
}
|
|
4876
|
+
return new Blob(chunks).bytes();
|
|
4881
4877
|
}
|
|
4882
4878
|
|
|
4883
4879
|
// src/sdk/ws.ts
|
|
4884
4880
|
async function resolveWS() {
|
|
4885
|
-
if (typeof
|
|
4886
|
-
return
|
|
4881
|
+
if (typeof WebSocket !== "undefined") {
|
|
4882
|
+
return WebSocket;
|
|
4887
4883
|
}
|
|
4888
4884
|
const dynamicImport = new Function("m", "return import(m)");
|
|
4889
4885
|
try {
|
|
@@ -4897,9 +4893,54 @@ async function resolveWS() {
|
|
|
4897
4893
|
throw err;
|
|
4898
4894
|
}
|
|
4899
4895
|
}
|
|
4896
|
+
async function openWebSocket({
|
|
4897
|
+
url,
|
|
4898
|
+
nameOrAddress,
|
|
4899
|
+
wsProtocol,
|
|
4900
|
+
authToken,
|
|
4901
|
+
compression,
|
|
4902
|
+
lightMode,
|
|
4903
|
+
confirmedReads
|
|
4904
|
+
}) {
|
|
4905
|
+
const headers = new Headers();
|
|
4906
|
+
const WS = await resolveWS();
|
|
4907
|
+
let temporaryAuthToken;
|
|
4908
|
+
if (authToken) {
|
|
4909
|
+
headers.set("Authorization", `Bearer ${authToken}`);
|
|
4910
|
+
const tokenUrl = new URL("v1/identity/websocket-token", url);
|
|
4911
|
+
tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
4912
|
+
const response = await fetch(tokenUrl, { method: "POST", headers });
|
|
4913
|
+
if (response.ok) {
|
|
4914
|
+
const { token } = await response.json();
|
|
4915
|
+
temporaryAuthToken = token;
|
|
4916
|
+
} else {
|
|
4917
|
+
throw new Error(`Failed to verify token: ${response.statusText}`);
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
|
|
4921
|
+
if (temporaryAuthToken) {
|
|
4922
|
+
databaseUrl.searchParams.set("token", temporaryAuthToken);
|
|
4923
|
+
}
|
|
4924
|
+
databaseUrl.searchParams.set(
|
|
4925
|
+
"compression",
|
|
4926
|
+
{ gzip: "Gzip", brotli: "Brotli", none: "None" }[compression] ?? "None"
|
|
4927
|
+
);
|
|
4928
|
+
if (lightMode) {
|
|
4929
|
+
databaseUrl.searchParams.set("light", "true");
|
|
4930
|
+
}
|
|
4931
|
+
if (confirmedReads !== void 0) {
|
|
4932
|
+
databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
|
|
4933
|
+
}
|
|
4934
|
+
const ws = new WS(databaseUrl.toString(), wsProtocol);
|
|
4935
|
+
ws.binaryType = "arraybuffer";
|
|
4936
|
+
return ws;
|
|
4937
|
+
}
|
|
4900
4938
|
|
|
4901
4939
|
// src/sdk/websocket_decompress_adapter.ts
|
|
4902
4940
|
var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
4941
|
+
get protocol() {
|
|
4942
|
+
return this.#ws.protocol;
|
|
4943
|
+
}
|
|
4903
4944
|
set onclose(handler) {
|
|
4904
4945
|
this.#ws.onclose = handler;
|
|
4905
4946
|
}
|
|
@@ -4923,9 +4964,7 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
4923
4964
|
case 0:
|
|
4924
4965
|
return data;
|
|
4925
4966
|
case 1:
|
|
4926
|
-
|
|
4927
|
-
"Brotli Compression not supported. Please use gzip or none compression in withCompression method on DbConnection."
|
|
4928
|
-
);
|
|
4967
|
+
return await decompress(data, "brotli");
|
|
4929
4968
|
case 2:
|
|
4930
4969
|
return await decompress(data, "gzip");
|
|
4931
4970
|
default:
|
|
@@ -4941,51 +4980,10 @@ var WebsocketDecompressAdapter = class _WebsocketDecompressAdapter {
|
|
|
4941
4980
|
this.#ws.close();
|
|
4942
4981
|
}
|
|
4943
4982
|
constructor(ws) {
|
|
4944
|
-
ws.binaryType = "arraybuffer";
|
|
4945
4983
|
this.#ws = ws;
|
|
4946
4984
|
}
|
|
4947
|
-
static async
|
|
4948
|
-
|
|
4949
|
-
nameOrAddress,
|
|
4950
|
-
wsProtocol,
|
|
4951
|
-
authToken,
|
|
4952
|
-
compression,
|
|
4953
|
-
lightMode,
|
|
4954
|
-
confirmedReads
|
|
4955
|
-
}) {
|
|
4956
|
-
const headers = new Headers();
|
|
4957
|
-
const WS = await resolveWS();
|
|
4958
|
-
let temporaryAuthToken = void 0;
|
|
4959
|
-
if (authToken) {
|
|
4960
|
-
headers.set("Authorization", `Bearer ${authToken}`);
|
|
4961
|
-
const tokenUrl = new URL("v1/identity/websocket-token", url);
|
|
4962
|
-
tokenUrl.protocol = url.protocol === "wss:" ? "https:" : "http:";
|
|
4963
|
-
const response = await fetch(tokenUrl, { method: "POST", headers });
|
|
4964
|
-
if (response.ok) {
|
|
4965
|
-
const { token } = await response.json();
|
|
4966
|
-
temporaryAuthToken = token;
|
|
4967
|
-
} else {
|
|
4968
|
-
return Promise.reject(
|
|
4969
|
-
new Error(`Failed to verify token: ${response.statusText}`)
|
|
4970
|
-
);
|
|
4971
|
-
}
|
|
4972
|
-
}
|
|
4973
|
-
const databaseUrl = new URL(`v1/database/${nameOrAddress}/subscribe`, url);
|
|
4974
|
-
if (temporaryAuthToken) {
|
|
4975
|
-
databaseUrl.searchParams.set("token", temporaryAuthToken);
|
|
4976
|
-
}
|
|
4977
|
-
databaseUrl.searchParams.set(
|
|
4978
|
-
"compression",
|
|
4979
|
-
compression === "gzip" ? "Gzip" : "None"
|
|
4980
|
-
);
|
|
4981
|
-
if (lightMode) {
|
|
4982
|
-
databaseUrl.searchParams.set("light", "true");
|
|
4983
|
-
}
|
|
4984
|
-
if (confirmedReads !== void 0) {
|
|
4985
|
-
databaseUrl.searchParams.set("confirmed", confirmedReads.toString());
|
|
4986
|
-
}
|
|
4987
|
-
const ws = new WS(databaseUrl.toString(), wsProtocol);
|
|
4988
|
-
return new _WebsocketDecompressAdapter(ws);
|
|
4985
|
+
static async openWebSocket(args) {
|
|
4986
|
+
return new _WebsocketDecompressAdapter(await openWebSocket(args));
|
|
4989
4987
|
}
|
|
4990
4988
|
};
|
|
4991
4989
|
|
|
@@ -5002,7 +5000,7 @@ var DbConnectionBuilder = class {
|
|
|
5002
5000
|
constructor(remoteModule, dbConnectionCtor) {
|
|
5003
5001
|
this.remoteModule = remoteModule;
|
|
5004
5002
|
this.dbConnectionCtor = dbConnectionCtor;
|
|
5005
|
-
this.#createWSFn = WebsocketDecompressAdapter.
|
|
5003
|
+
this.#createWSFn = WebsocketDecompressAdapter.openWebSocket;
|
|
5006
5004
|
}
|
|
5007
5005
|
#uri;
|
|
5008
5006
|
#nameOrAddress;
|
|
@@ -5057,6 +5055,16 @@ var DbConnectionBuilder = class {
|
|
|
5057
5055
|
* @param compression The compression algorithm to use for the connection.
|
|
5058
5056
|
*/
|
|
5059
5057
|
withCompression(compression) {
|
|
5058
|
+
if (compression === "brotli") {
|
|
5059
|
+
try {
|
|
5060
|
+
new DecompressionStream("brotli");
|
|
5061
|
+
} catch (e) {
|
|
5062
|
+
throw new TypeError(
|
|
5063
|
+
`Brotli compression is not supported by the runtime. Please choose a different compression method.`,
|
|
5064
|
+
{ cause: e }
|
|
5065
|
+
);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5060
5068
|
this.#compression = compression;
|
|
5061
5069
|
return this;
|
|
5062
5070
|
}
|
|
@@ -5420,6 +5428,100 @@ var SubscriptionHandleImpl = class {
|
|
|
5420
5428
|
return this.#activeState;
|
|
5421
5429
|
}
|
|
5422
5430
|
};
|
|
5431
|
+
|
|
5432
|
+
// src/sdk/websocket_protocols.ts
|
|
5433
|
+
var V2_WS_PROTOCOL = "v2.bsatn.spacetimedb";
|
|
5434
|
+
var V3_WS_PROTOCOL = "v3.bsatn.spacetimedb";
|
|
5435
|
+
var PREFERRED_WS_PROTOCOLS = [V3_WS_PROTOCOL, V2_WS_PROTOCOL];
|
|
5436
|
+
function normalizeWsProtocol(protocol) {
|
|
5437
|
+
if (protocol === V3_WS_PROTOCOL) {
|
|
5438
|
+
return V3_WS_PROTOCOL;
|
|
5439
|
+
}
|
|
5440
|
+
if (protocol === "" || protocol === V2_WS_PROTOCOL) {
|
|
5441
|
+
return V2_WS_PROTOCOL;
|
|
5442
|
+
}
|
|
5443
|
+
stdbLogger(
|
|
5444
|
+
"warn",
|
|
5445
|
+
`Unexpected websocket subprotocol "${protocol}", falling back to ${V2_WS_PROTOCOL}.`
|
|
5446
|
+
);
|
|
5447
|
+
return V2_WS_PROTOCOL;
|
|
5448
|
+
}
|
|
5449
|
+
|
|
5450
|
+
// src/sdk/websocket_v3_frames.ts
|
|
5451
|
+
var EMPTY_V3_PAYLOAD_ERR = "v3 websocket payloads must contain at least one message";
|
|
5452
|
+
function ensureMessages(messages) {
|
|
5453
|
+
if (messages.length === 0) {
|
|
5454
|
+
throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
function ensureMessageCount(messages, messageCount) {
|
|
5458
|
+
ensureMessages(messages);
|
|
5459
|
+
if (messageCount < 1 || messageCount > messages.length) {
|
|
5460
|
+
throw new RangeError(
|
|
5461
|
+
`v3 websocket payload requested ${messageCount} messages from ${messages.length}`
|
|
5462
|
+
);
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
function concatenateMessagesV3(writer, messages, messageCount = messages.length) {
|
|
5466
|
+
ensureMessageCount(messages, messageCount);
|
|
5467
|
+
writer.clear();
|
|
5468
|
+
for (let i = 0; i < messageCount; i++) {
|
|
5469
|
+
writer.writeBytes(messages[i]);
|
|
5470
|
+
}
|
|
5471
|
+
return writer.getBuffer();
|
|
5472
|
+
}
|
|
5473
|
+
function countClientMessagesForV3Frame(messages, maxFrameBytes) {
|
|
5474
|
+
ensureMessages(messages);
|
|
5475
|
+
const firstMessage = messages[0];
|
|
5476
|
+
if (firstMessage.length > maxFrameBytes) {
|
|
5477
|
+
return 1;
|
|
5478
|
+
}
|
|
5479
|
+
let count = 1;
|
|
5480
|
+
let frameSize = firstMessage.length;
|
|
5481
|
+
while (count < messages.length) {
|
|
5482
|
+
const nextMessage = messages[count];
|
|
5483
|
+
const nextFrameSize = frameSize + nextMessage.length;
|
|
5484
|
+
if (nextFrameSize > maxFrameBytes) {
|
|
5485
|
+
break;
|
|
5486
|
+
}
|
|
5487
|
+
frameSize = nextFrameSize;
|
|
5488
|
+
count += 1;
|
|
5489
|
+
}
|
|
5490
|
+
return count;
|
|
5491
|
+
}
|
|
5492
|
+
function encodeClientMessagesV3(writer, messages, messageCount = messages.length) {
|
|
5493
|
+
return concatenateMessagesV3(writer, messages, messageCount);
|
|
5494
|
+
}
|
|
5495
|
+
function forEachServerMessageV3(reader, data, visit) {
|
|
5496
|
+
reader.reset(data);
|
|
5497
|
+
if (reader.remaining === 0) {
|
|
5498
|
+
throw new RangeError(EMPTY_V3_PAYLOAD_ERR);
|
|
5499
|
+
}
|
|
5500
|
+
let count = 0;
|
|
5501
|
+
while (reader.remaining > 0) {
|
|
5502
|
+
visit(ServerMessage.deserialize(reader));
|
|
5503
|
+
count += 1;
|
|
5504
|
+
}
|
|
5505
|
+
return count;
|
|
5506
|
+
}
|
|
5507
|
+
|
|
5508
|
+
// src/sdk/db_connection_impl.ts
|
|
5509
|
+
var TEXT_ENCODER = new TextEncoder();
|
|
5510
|
+
function getClientMessageVariantTag(name) {
|
|
5511
|
+
if (ClientMessage.algebraicType.tag !== "Sum") {
|
|
5512
|
+
throw new TypeError("ClientMessage must be a sum type");
|
|
5513
|
+
}
|
|
5514
|
+
const tag = ClientMessage.algebraicType.value.variants.findIndex(
|
|
5515
|
+
(variant) => variant.name === name
|
|
5516
|
+
);
|
|
5517
|
+
if (tag === -1) {
|
|
5518
|
+
throw new RangeError(`Unknown ClientMessage variant: ${name}`);
|
|
5519
|
+
}
|
|
5520
|
+
return tag;
|
|
5521
|
+
}
|
|
5522
|
+
var CLIENT_MESSAGE_CALL_REDUCER_TAG = getClientMessageVariantTag("CallReducer");
|
|
5523
|
+
var CLIENT_MESSAGE_CALL_PROCEDURE_TAG = getClientMessageVariantTag("CallProcedure");
|
|
5524
|
+
var MAX_V3_OUTBOUND_FRAME_BYTES = 256 * 1024;
|
|
5423
5525
|
var DbConnectionImpl = class {
|
|
5424
5526
|
/**
|
|
5425
5527
|
* Whether or not the connection is active.
|
|
@@ -5454,22 +5556,35 @@ var DbConnectionImpl = class {
|
|
|
5454
5556
|
* The `ConnectionId` of the connection to to the database.
|
|
5455
5557
|
*/
|
|
5456
5558
|
connectionId = ConnectionId.random();
|
|
5559
|
+
#connectionIdHex = this.connectionId.toHexString();
|
|
5457
5560
|
// These fields are meant to be strictly private.
|
|
5458
5561
|
#queryId = 0;
|
|
5459
5562
|
#requestId = 0;
|
|
5460
5563
|
#eventId = 0;
|
|
5461
5564
|
#emitter;
|
|
5462
|
-
#
|
|
5565
|
+
#inboundQueue = [];
|
|
5566
|
+
#inboundQueueOffset = 0;
|
|
5567
|
+
#isDrainingInboundQueue = false;
|
|
5463
5568
|
#outboundQueue = [];
|
|
5569
|
+
#isOutboundFlushScheduled = false;
|
|
5570
|
+
#negotiatedWsProtocol = V2_WS_PROTOCOL;
|
|
5464
5571
|
#subscriptionManager = new SubscriptionManager();
|
|
5465
5572
|
#remoteModule;
|
|
5466
5573
|
#reducerCallbacks = /* @__PURE__ */ new Map();
|
|
5467
5574
|
#reducerCallInfo = /* @__PURE__ */ new Map();
|
|
5468
5575
|
#procedureCallbacks = /* @__PURE__ */ new Map();
|
|
5469
5576
|
#rowDeserializers;
|
|
5577
|
+
#rowIdMetadata;
|
|
5470
5578
|
#reducerArgsSerializers;
|
|
5471
5579
|
#procedureSerializers;
|
|
5580
|
+
#reducerNameBytes;
|
|
5581
|
+
#procedureNameBytes;
|
|
5472
5582
|
#sourceNameToTableDef;
|
|
5583
|
+
#messageReader = new BinaryReader(new Uint8Array());
|
|
5584
|
+
#rowListReader = new BinaryReader(new Uint8Array());
|
|
5585
|
+
#clientFrameEncoder = new BinaryWriter(1024);
|
|
5586
|
+
#boundSubscriptionBuilder;
|
|
5587
|
+
#boundDisconnect;
|
|
5473
5588
|
// These fields are not part of the public API, but in a pinch you
|
|
5474
5589
|
// could use JavaScript to access them by bypassing TypeScript's
|
|
5475
5590
|
// private fields.
|
|
@@ -5498,22 +5613,35 @@ var DbConnectionImpl = class {
|
|
|
5498
5613
|
this.token = token;
|
|
5499
5614
|
this.#remoteModule = remoteModule;
|
|
5500
5615
|
this.#emitter = emitter;
|
|
5616
|
+
this.#boundSubscriptionBuilder = this.subscriptionBuilder.bind(this);
|
|
5617
|
+
this.#boundDisconnect = this.disconnect.bind(this);
|
|
5501
5618
|
this.#rowDeserializers = /* @__PURE__ */ Object.create(null);
|
|
5619
|
+
this.#rowIdMetadata = /* @__PURE__ */ Object.create(null);
|
|
5502
5620
|
this.#sourceNameToTableDef = /* @__PURE__ */ Object.create(null);
|
|
5503
5621
|
for (const table2 of Object.values(remoteModule.tables)) {
|
|
5504
5622
|
this.#rowDeserializers[table2.sourceName] = ProductType.makeDeserializer(
|
|
5505
5623
|
table2.rowType
|
|
5506
5624
|
);
|
|
5507
5625
|
this.#sourceNameToTableDef[table2.sourceName] = table2;
|
|
5626
|
+
const primaryKeyColumn = Object.entries(table2.columns).find(
|
|
5627
|
+
([, column]) => column.columnMetadata.isPrimaryKey
|
|
5628
|
+
);
|
|
5629
|
+
this.#rowIdMetadata[table2.sourceName] = primaryKeyColumn ? {
|
|
5630
|
+
primaryKeyColName: primaryKeyColumn[0],
|
|
5631
|
+
primaryKeyColType: primaryKeyColumn[1].typeBuilder.algebraicType
|
|
5632
|
+
} : {};
|
|
5508
5633
|
}
|
|
5509
5634
|
this.#reducerArgsSerializers = /* @__PURE__ */ Object.create(null);
|
|
5635
|
+
this.#reducerNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5510
5636
|
for (const reducer of remoteModule.reducers) {
|
|
5511
5637
|
this.#reducerArgsSerializers[reducer.name] = {
|
|
5512
5638
|
serialize: ProductType.makeSerializer(reducer.paramsType),
|
|
5513
5639
|
deserialize: ProductType.makeDeserializer(reducer.paramsType)
|
|
5514
5640
|
};
|
|
5641
|
+
this.#reducerNameBytes[reducer.name] = TEXT_ENCODER.encode(reducer.name);
|
|
5515
5642
|
}
|
|
5516
5643
|
this.#procedureSerializers = /* @__PURE__ */ Object.create(null);
|
|
5644
|
+
this.#procedureNameBytes = /* @__PURE__ */ Object.create(null);
|
|
5517
5645
|
for (const procedure of remoteModule.procedures) {
|
|
5518
5646
|
this.#procedureSerializers[procedure.name] = {
|
|
5519
5647
|
serializeArgs: ProductType.makeSerializer(
|
|
@@ -5523,9 +5651,11 @@ var DbConnectionImpl = class {
|
|
|
5523
5651
|
procedure.returnType.algebraicType
|
|
5524
5652
|
)
|
|
5525
5653
|
};
|
|
5654
|
+
this.#procedureNameBytes[procedure.name] = TEXT_ENCODER.encode(
|
|
5655
|
+
procedure.name
|
|
5656
|
+
);
|
|
5526
5657
|
}
|
|
5527
|
-
|
|
5528
|
-
url.searchParams.set("connection_id", connectionId);
|
|
5658
|
+
url.searchParams.set("connection_id", this.#connectionIdHex);
|
|
5529
5659
|
this.clientCache = new ClientCache();
|
|
5530
5660
|
this.db = this.#makeDbView();
|
|
5531
5661
|
this.reducers = this.#makeReducers(remoteModule);
|
|
@@ -5533,7 +5663,7 @@ var DbConnectionImpl = class {
|
|
|
5533
5663
|
this.wsPromise = createWSFn({
|
|
5534
5664
|
url,
|
|
5535
5665
|
nameOrAddress,
|
|
5536
|
-
wsProtocol:
|
|
5666
|
+
wsProtocol: [...PREFERRED_WS_PROTOCOLS],
|
|
5537
5667
|
authToken: token,
|
|
5538
5668
|
compression,
|
|
5539
5669
|
lightMode,
|
|
@@ -5577,16 +5707,22 @@ var DbConnectionImpl = class {
|
|
|
5577
5707
|
}
|
|
5578
5708
|
#makeReducers(def) {
|
|
5579
5709
|
const out = {};
|
|
5580
|
-
const writer = new BinaryWriter(1024);
|
|
5581
5710
|
for (const reducer of def.reducers) {
|
|
5582
5711
|
const reducerName = reducer.name;
|
|
5712
|
+
const encodedReducerName = this.#reducerNameBytes[reducerName];
|
|
5583
5713
|
const key = reducer.accessorName;
|
|
5584
5714
|
const { serialize: serializeArgs } = this.#reducerArgsSerializers[reducerName];
|
|
5585
5715
|
out[key] = (params) => {
|
|
5716
|
+
const writer = this.#reducerArgsEncoder;
|
|
5586
5717
|
writer.clear();
|
|
5587
5718
|
serializeArgs(writer, params);
|
|
5588
5719
|
const argsBuffer = writer.getBuffer();
|
|
5589
|
-
return this
|
|
5720
|
+
return this.#callReducerWithEncodedName(
|
|
5721
|
+
reducerName,
|
|
5722
|
+
encodedReducerName,
|
|
5723
|
+
argsBuffer,
|
|
5724
|
+
params
|
|
5725
|
+
);
|
|
5590
5726
|
};
|
|
5591
5727
|
}
|
|
5592
5728
|
return out;
|
|
@@ -5596,13 +5732,18 @@ var DbConnectionImpl = class {
|
|
|
5596
5732
|
const writer = new BinaryWriter(1024);
|
|
5597
5733
|
for (const procedure of def.procedures) {
|
|
5598
5734
|
const procedureName = procedure.name;
|
|
5735
|
+
const encodedProcedureName = this.#procedureNameBytes[procedureName];
|
|
5599
5736
|
const key = procedure.accessorName;
|
|
5600
5737
|
const { serializeArgs, deserializeReturn } = this.#procedureSerializers[procedureName];
|
|
5601
5738
|
out[key] = (params) => {
|
|
5602
5739
|
writer.clear();
|
|
5603
5740
|
serializeArgs(writer, params);
|
|
5604
5741
|
const argsBuffer = writer.getBuffer();
|
|
5605
|
-
return this
|
|
5742
|
+
return this.#callProcedureWithEncodedName(
|
|
5743
|
+
procedureName,
|
|
5744
|
+
encodedProcedureName,
|
|
5745
|
+
argsBuffer
|
|
5746
|
+
).then((returnBuf) => {
|
|
5606
5747
|
return deserializeReturn(new BinaryReader(returnBuf));
|
|
5607
5748
|
});
|
|
5608
5749
|
};
|
|
@@ -5614,8 +5755,8 @@ var DbConnectionImpl = class {
|
|
|
5614
5755
|
db: this.db,
|
|
5615
5756
|
reducers: this.reducers,
|
|
5616
5757
|
isActive: this.isActive,
|
|
5617
|
-
subscriptionBuilder: this
|
|
5618
|
-
disconnect: this
|
|
5758
|
+
subscriptionBuilder: this.#boundSubscriptionBuilder,
|
|
5759
|
+
disconnect: this.#boundDisconnect,
|
|
5619
5760
|
event
|
|
5620
5761
|
};
|
|
5621
5762
|
}
|
|
@@ -5660,21 +5801,16 @@ var DbConnectionImpl = class {
|
|
|
5660
5801
|
}
|
|
5661
5802
|
#parseRowList(type, tableName, rowList) {
|
|
5662
5803
|
const buffer = rowList.rowsData;
|
|
5663
|
-
const reader =
|
|
5804
|
+
const reader = this.#rowListReader;
|
|
5805
|
+
reader.reset(buffer);
|
|
5664
5806
|
const rows = [];
|
|
5665
5807
|
const deserializeRow = this.#rowDeserializers[tableName];
|
|
5666
|
-
const
|
|
5667
|
-
const columnsArray = Object.entries(table2.columns);
|
|
5668
|
-
const primaryKeyColumnEntry = columnsArray.find(
|
|
5669
|
-
(col) => col[1].columnMetadata.isPrimaryKey
|
|
5670
|
-
);
|
|
5808
|
+
const { primaryKeyColName, primaryKeyColType } = this.#rowIdMetadata[tableName];
|
|
5671
5809
|
let previousOffset = 0;
|
|
5672
5810
|
while (reader.remaining > 0) {
|
|
5673
5811
|
const row = deserializeRow(reader);
|
|
5674
5812
|
let rowId = void 0;
|
|
5675
|
-
if (
|
|
5676
|
-
const primaryKeyColName = primaryKeyColumnEntry[0];
|
|
5677
|
-
const primaryKeyColType = primaryKeyColumnEntry[1].typeBuilder.algebraicType;
|
|
5813
|
+
if (primaryKeyColName !== void 0 && primaryKeyColType !== void 0) {
|
|
5678
5814
|
rowId = AlgebraicType.intoMapKey(
|
|
5679
5815
|
primaryKeyColType,
|
|
5680
5816
|
row[primaryKeyColName]
|
|
@@ -5755,40 +5891,136 @@ var DbConnectionImpl = class {
|
|
|
5755
5891
|
return this.#mergeTableUpdates(updates);
|
|
5756
5892
|
}
|
|
5757
5893
|
#flushOutboundQueue(wsResolved) {
|
|
5894
|
+
if (this.#negotiatedWsProtocol === V3_WS_PROTOCOL) {
|
|
5895
|
+
this.#flushOutboundQueueV3(wsResolved);
|
|
5896
|
+
return;
|
|
5897
|
+
}
|
|
5898
|
+
this.#flushOutboundQueueV2(wsResolved);
|
|
5899
|
+
}
|
|
5900
|
+
#flushOutboundQueueV2(wsResolved) {
|
|
5758
5901
|
const pending = this.#outboundQueue.splice(0);
|
|
5759
5902
|
for (const message of pending) {
|
|
5760
5903
|
wsResolved.send(message);
|
|
5761
5904
|
}
|
|
5762
5905
|
}
|
|
5906
|
+
#flushOutboundQueueV3(wsResolved) {
|
|
5907
|
+
if (this.#outboundQueue.length === 0) {
|
|
5908
|
+
return;
|
|
5909
|
+
}
|
|
5910
|
+
const batchSize = countClientMessagesForV3Frame(
|
|
5911
|
+
this.#outboundQueue,
|
|
5912
|
+
MAX_V3_OUTBOUND_FRAME_BYTES
|
|
5913
|
+
);
|
|
5914
|
+
wsResolved.send(
|
|
5915
|
+
encodeClientMessagesV3(
|
|
5916
|
+
this.#clientFrameEncoder,
|
|
5917
|
+
this.#outboundQueue,
|
|
5918
|
+
batchSize
|
|
5919
|
+
)
|
|
5920
|
+
);
|
|
5921
|
+
if (batchSize === this.#outboundQueue.length) {
|
|
5922
|
+
this.#outboundQueue.length = 0;
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5925
|
+
this.#outboundQueue.copyWithin(0, batchSize);
|
|
5926
|
+
this.#outboundQueue.length -= batchSize;
|
|
5927
|
+
if (this.#outboundQueue.length > 0) {
|
|
5928
|
+
this.#scheduleDeferredOutboundFlush();
|
|
5929
|
+
}
|
|
5930
|
+
}
|
|
5931
|
+
#scheduleOutboundFlush() {
|
|
5932
|
+
this.#scheduleOutboundFlushWith("microtask");
|
|
5933
|
+
}
|
|
5934
|
+
#scheduleDeferredOutboundFlush() {
|
|
5935
|
+
this.#scheduleOutboundFlushWith("next-task");
|
|
5936
|
+
}
|
|
5937
|
+
#scheduleOutboundFlushWith(schedule) {
|
|
5938
|
+
if (this.#isOutboundFlushScheduled) {
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
this.#isOutboundFlushScheduled = true;
|
|
5942
|
+
const flush = () => {
|
|
5943
|
+
this.#isOutboundFlushScheduled = false;
|
|
5944
|
+
if (this.ws && this.isActive) {
|
|
5945
|
+
this.#flushOutboundQueue(this.ws);
|
|
5946
|
+
}
|
|
5947
|
+
};
|
|
5948
|
+
if (schedule === "next-task") {
|
|
5949
|
+
setTimeout(flush, 0);
|
|
5950
|
+
} else {
|
|
5951
|
+
queueMicrotask(flush);
|
|
5952
|
+
}
|
|
5953
|
+
}
|
|
5954
|
+
#reducerArgsEncoder = new BinaryWriter(1024);
|
|
5763
5955
|
#clientMessageEncoder = new BinaryWriter(1024);
|
|
5956
|
+
#sendEncodedMessage(encoded, describe) {
|
|
5957
|
+
stdbLogger("trace", describe);
|
|
5958
|
+
if (this.ws && this.isActive) {
|
|
5959
|
+
if (this.#negotiatedWsProtocol === V2_WS_PROTOCOL) {
|
|
5960
|
+
if (this.#outboundQueue.length) this.#flushOutboundQueue(this.ws);
|
|
5961
|
+
this.ws.send(encoded);
|
|
5962
|
+
return;
|
|
5963
|
+
}
|
|
5964
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5965
|
+
this.#scheduleOutboundFlush();
|
|
5966
|
+
} else {
|
|
5967
|
+
this.#outboundQueue.push(encoded.slice());
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5764
5970
|
#sendMessage(message) {
|
|
5765
5971
|
const writer = this.#clientMessageEncoder;
|
|
5766
5972
|
writer.clear();
|
|
5767
5973
|
ClientMessage.serialize(writer, message);
|
|
5768
5974
|
const encoded = writer.getBuffer();
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5975
|
+
const isLive = !!(this.ws && this.isActive);
|
|
5976
|
+
this.#sendEncodedMessage(
|
|
5977
|
+
encoded,
|
|
5978
|
+
() => isLive ? `Sending message to server: ${stringify(message)}` : `Queuing message to server: ${stringify(message)}`
|
|
5979
|
+
);
|
|
5980
|
+
}
|
|
5981
|
+
#sendCallReducerMessage(requestId, reducerNameBytes, argsBuffer) {
|
|
5982
|
+
const writer = this.#clientMessageEncoder;
|
|
5983
|
+
writer.clear();
|
|
5984
|
+
writer.writeByte(CLIENT_MESSAGE_CALL_REDUCER_TAG);
|
|
5985
|
+
writer.writeU32(requestId);
|
|
5986
|
+
writer.writeU8(0);
|
|
5987
|
+
writer.writeUInt8Array(reducerNameBytes);
|
|
5988
|
+
writer.writeUInt8Array(argsBuffer);
|
|
5989
|
+
const encoded = writer.getBuffer();
|
|
5990
|
+
this.#sendEncodedMessage(
|
|
5991
|
+
encoded,
|
|
5992
|
+
() => `Sending reducer call message to server: requestId=${requestId}`
|
|
5993
|
+
);
|
|
5994
|
+
}
|
|
5995
|
+
#sendCallProcedureMessage(requestId, procedureNameBytes, argsBuffer) {
|
|
5996
|
+
const writer = this.#clientMessageEncoder;
|
|
5997
|
+
writer.clear();
|
|
5998
|
+
writer.writeByte(CLIENT_MESSAGE_CALL_PROCEDURE_TAG);
|
|
5999
|
+
writer.writeU32(requestId);
|
|
6000
|
+
writer.writeU8(0);
|
|
6001
|
+
writer.writeUInt8Array(procedureNameBytes);
|
|
6002
|
+
writer.writeUInt8Array(argsBuffer);
|
|
6003
|
+
const encoded = writer.getBuffer();
|
|
6004
|
+
this.#sendEncodedMessage(
|
|
6005
|
+
encoded,
|
|
6006
|
+
() => `Sending procedure call message to server: requestId=${requestId}`
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
#setConnectionId(connectionId) {
|
|
6010
|
+
this.connectionId = connectionId;
|
|
6011
|
+
this.#connectionIdHex = connectionId.toHexString();
|
|
5783
6012
|
}
|
|
5784
6013
|
#nextEventId() {
|
|
5785
6014
|
this.#eventId += 1;
|
|
5786
|
-
return `${this
|
|
6015
|
+
return `${this.#connectionIdHex}:${this.#eventId}`;
|
|
5787
6016
|
}
|
|
5788
6017
|
/**
|
|
5789
6018
|
* Handles WebSocket onOpen event.
|
|
5790
6019
|
*/
|
|
5791
6020
|
#handleOnOpen() {
|
|
6021
|
+
if (this.ws) {
|
|
6022
|
+
this.#negotiatedWsProtocol = normalizeWsProtocol(this.ws.protocol);
|
|
6023
|
+
}
|
|
5792
6024
|
this.isActive = true;
|
|
5793
6025
|
if (this.ws) {
|
|
5794
6026
|
this.#flushOutboundQueue(this.ws);
|
|
@@ -5823,8 +6055,16 @@ var DbConnectionImpl = class {
|
|
|
5823
6055
|
eventContext
|
|
5824
6056
|
);
|
|
5825
6057
|
}
|
|
5826
|
-
|
|
5827
|
-
|
|
6058
|
+
#dispatchPendingCallbacks(callbacks) {
|
|
6059
|
+
stdbLogger(
|
|
6060
|
+
"trace",
|
|
6061
|
+
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
6062
|
+
);
|
|
6063
|
+
for (const callback of callbacks) {
|
|
6064
|
+
callback.cb();
|
|
6065
|
+
}
|
|
6066
|
+
}
|
|
6067
|
+
#processServerMessage(serverMessage) {
|
|
5828
6068
|
stdbLogger(
|
|
5829
6069
|
"trace",
|
|
5830
6070
|
() => `Processing server message: ${stringify(serverMessage)}`
|
|
@@ -5835,7 +6075,7 @@ var DbConnectionImpl = class {
|
|
|
5835
6075
|
if (!this.token && serverMessage.value.token) {
|
|
5836
6076
|
this.token = serverMessage.value.token;
|
|
5837
6077
|
}
|
|
5838
|
-
this
|
|
6078
|
+
this.#setConnectionId(serverMessage.value.connectionId);
|
|
5839
6079
|
this.#emitter.emit("connect", this, this.identity, this.token);
|
|
5840
6080
|
break;
|
|
5841
6081
|
}
|
|
@@ -5861,13 +6101,7 @@ var DbConnectionImpl = class {
|
|
|
5861
6101
|
const callbacks = this.#applyTableUpdates(tableUpdates, eventContext);
|
|
5862
6102
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
5863
6103
|
subscription.emitter.emit("applied", subscriptionEventContext);
|
|
5864
|
-
|
|
5865
|
-
"trace",
|
|
5866
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5867
|
-
);
|
|
5868
|
-
for (const callback of callbacks) {
|
|
5869
|
-
callback.cb();
|
|
5870
|
-
}
|
|
6104
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5871
6105
|
break;
|
|
5872
6106
|
}
|
|
5873
6107
|
case "UnsubscribeApplied": {
|
|
@@ -5890,13 +6124,7 @@ var DbConnectionImpl = class {
|
|
|
5890
6124
|
const { event: _, ...subscriptionEventContext } = eventContext;
|
|
5891
6125
|
subscription.emitter.emit("end", subscriptionEventContext);
|
|
5892
6126
|
this.#subscriptionManager.subscriptions.delete(querySetId);
|
|
5893
|
-
|
|
5894
|
-
"trace",
|
|
5895
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5896
|
-
);
|
|
5897
|
-
for (const callback of callbacks) {
|
|
5898
|
-
callback.cb();
|
|
5899
|
-
}
|
|
6127
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5900
6128
|
break;
|
|
5901
6129
|
}
|
|
5902
6130
|
case "SubscriptionError": {
|
|
@@ -5944,13 +6172,7 @@ var DbConnectionImpl = class {
|
|
|
5944
6172
|
eventContext,
|
|
5945
6173
|
serverMessage.value
|
|
5946
6174
|
);
|
|
5947
|
-
|
|
5948
|
-
"trace",
|
|
5949
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5950
|
-
);
|
|
5951
|
-
for (const callback of callbacks) {
|
|
5952
|
-
callback.cb();
|
|
5953
|
-
}
|
|
6175
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5954
6176
|
break;
|
|
5955
6177
|
}
|
|
5956
6178
|
case "ReducerResult": {
|
|
@@ -5978,13 +6200,7 @@ var DbConnectionImpl = class {
|
|
|
5978
6200
|
eventContext,
|
|
5979
6201
|
result.value.transactionUpdate
|
|
5980
6202
|
);
|
|
5981
|
-
|
|
5982
|
-
"trace",
|
|
5983
|
-
() => `Calling ${callbacks.length} triggered row callbacks`
|
|
5984
|
-
);
|
|
5985
|
-
for (const callback of callbacks) {
|
|
5986
|
-
callback.cb();
|
|
5987
|
-
}
|
|
6203
|
+
this.#dispatchPendingCallbacks(callbacks);
|
|
5988
6204
|
}
|
|
5989
6205
|
this.#reducerCallInfo.delete(requestId);
|
|
5990
6206
|
const cb = this.#reducerCallbacks.get(requestId);
|
|
@@ -6009,14 +6225,55 @@ var DbConnectionImpl = class {
|
|
|
6009
6225
|
}
|
|
6010
6226
|
}
|
|
6011
6227
|
}
|
|
6228
|
+
#processV2Message(data) {
|
|
6229
|
+
const reader = this.#messageReader;
|
|
6230
|
+
reader.reset(data);
|
|
6231
|
+
this.#processServerMessage(ServerMessage.deserialize(reader));
|
|
6232
|
+
}
|
|
6233
|
+
#processMessage(data) {
|
|
6234
|
+
if (this.#negotiatedWsProtocol !== V3_WS_PROTOCOL) {
|
|
6235
|
+
this.#processV2Message(data);
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
const messageCount = forEachServerMessageV3(
|
|
6239
|
+
this.#messageReader,
|
|
6240
|
+
data,
|
|
6241
|
+
(serverMessage) => {
|
|
6242
|
+
this.#processServerMessage(serverMessage);
|
|
6243
|
+
}
|
|
6244
|
+
);
|
|
6245
|
+
stdbLogger(
|
|
6246
|
+
"trace",
|
|
6247
|
+
() => `Processing server v3 payload with ${messageCount} message(s)`
|
|
6248
|
+
);
|
|
6249
|
+
}
|
|
6012
6250
|
/**
|
|
6013
6251
|
* Handles WebSocket onMessage event.
|
|
6014
6252
|
* @param wsMessage MessageEvent object.
|
|
6015
6253
|
*/
|
|
6016
6254
|
#handleOnMessage(wsMessage) {
|
|
6017
|
-
this.#
|
|
6018
|
-
|
|
6019
|
-
|
|
6255
|
+
this.#inboundQueue.push(wsMessage.data);
|
|
6256
|
+
if (this.#isDrainingInboundQueue) {
|
|
6257
|
+
return;
|
|
6258
|
+
}
|
|
6259
|
+
this.#isDrainingInboundQueue = true;
|
|
6260
|
+
try {
|
|
6261
|
+
while (this.#inboundQueueOffset < this.#inboundQueue.length) {
|
|
6262
|
+
const data = this.#inboundQueue[this.#inboundQueueOffset];
|
|
6263
|
+
this.#inboundQueueOffset += 1;
|
|
6264
|
+
if (data) {
|
|
6265
|
+
this.#processMessage(data);
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
} finally {
|
|
6269
|
+
if (this.#inboundQueueOffset >= this.#inboundQueue.length) {
|
|
6270
|
+
this.#inboundQueue.length = 0;
|
|
6271
|
+
} else if (this.#inboundQueueOffset > 0) {
|
|
6272
|
+
this.#inboundQueue = this.#inboundQueue.slice(this.#inboundQueueOffset);
|
|
6273
|
+
}
|
|
6274
|
+
this.#inboundQueueOffset = 0;
|
|
6275
|
+
this.#isDrainingInboundQueue = false;
|
|
6276
|
+
}
|
|
6020
6277
|
}
|
|
6021
6278
|
/**
|
|
6022
6279
|
* Call a reducer on your SpacetimeDB module.
|
|
@@ -6025,6 +6282,45 @@ var DbConnectionImpl = class {
|
|
|
6025
6282
|
* @param argsSerializer The arguments to pass to the reducer
|
|
6026
6283
|
*/
|
|
6027
6284
|
callReducer(reducerName, argsBuffer, reducerArgs) {
|
|
6285
|
+
const encodedReducerName = this.#reducerNameBytes[reducerName];
|
|
6286
|
+
if (encodedReducerName) {
|
|
6287
|
+
return this.#callReducerWithEncodedName(
|
|
6288
|
+
reducerName,
|
|
6289
|
+
encodedReducerName,
|
|
6290
|
+
argsBuffer,
|
|
6291
|
+
reducerArgs
|
|
6292
|
+
);
|
|
6293
|
+
}
|
|
6294
|
+
return this.#callReducerGeneric(reducerName, argsBuffer, reducerArgs);
|
|
6295
|
+
}
|
|
6296
|
+
#callReducerWithEncodedName(reducerName, encodedReducerName, argsBuffer, reducerArgs) {
|
|
6297
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6298
|
+
const requestId = this.#getNextRequestId();
|
|
6299
|
+
this.#sendCallReducerMessage(requestId, encodedReducerName, argsBuffer);
|
|
6300
|
+
if (reducerArgs) {
|
|
6301
|
+
this.#reducerCallInfo.set(requestId, {
|
|
6302
|
+
name: reducerName,
|
|
6303
|
+
args: reducerArgs
|
|
6304
|
+
});
|
|
6305
|
+
}
|
|
6306
|
+
this.#reducerCallbacks.set(requestId, (result) => {
|
|
6307
|
+
if (result.tag === "Ok" || result.tag === "OkEmpty") {
|
|
6308
|
+
resolve();
|
|
6309
|
+
} else {
|
|
6310
|
+
if (result.tag === "Err") {
|
|
6311
|
+
const reader = new BinaryReader(result.value);
|
|
6312
|
+
const errorString = reader.readString();
|
|
6313
|
+
reject(new SenderError(errorString));
|
|
6314
|
+
} else if (result.tag === "InternalError") {
|
|
6315
|
+
reject(new InternalError(result.value));
|
|
6316
|
+
} else {
|
|
6317
|
+
reject(new Error("Unexpected reducer result"));
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
});
|
|
6321
|
+
return promise;
|
|
6322
|
+
}
|
|
6323
|
+
#callReducerGeneric(reducerName, argsBuffer, reducerArgs) {
|
|
6028
6324
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6029
6325
|
const requestId = this.#getNextRequestId();
|
|
6030
6326
|
const message = ClientMessage.CallReducer({
|
|
@@ -6064,7 +6360,8 @@ var DbConnectionImpl = class {
|
|
|
6064
6360
|
* @param params The arguments to pass to the reducer
|
|
6065
6361
|
*/
|
|
6066
6362
|
callReducerWithParams(reducerName, _paramsType, params) {
|
|
6067
|
-
const writer =
|
|
6363
|
+
const writer = this.#reducerArgsEncoder;
|
|
6364
|
+
writer.clear();
|
|
6068
6365
|
this.#reducerArgsSerializers[reducerName].serialize(writer, params);
|
|
6069
6366
|
const argsBuffer = writer.getBuffer();
|
|
6070
6367
|
return this.callReducer(reducerName, argsBuffer, params);
|
|
@@ -6076,6 +6373,30 @@ var DbConnectionImpl = class {
|
|
|
6076
6373
|
* @param argsBuffer The arguments to pass to the reducer
|
|
6077
6374
|
*/
|
|
6078
6375
|
callProcedure(procedureName, argsBuffer) {
|
|
6376
|
+
const encodedProcedureName = this.#procedureNameBytes[procedureName];
|
|
6377
|
+
if (encodedProcedureName) {
|
|
6378
|
+
return this.#callProcedureWithEncodedName(
|
|
6379
|
+
procedureName,
|
|
6380
|
+
encodedProcedureName,
|
|
6381
|
+
argsBuffer
|
|
6382
|
+
);
|
|
6383
|
+
}
|
|
6384
|
+
return this.#callProcedureGeneric(procedureName, argsBuffer);
|
|
6385
|
+
}
|
|
6386
|
+
#callProcedureWithEncodedName(procedureName, encodedProcedureName, argsBuffer) {
|
|
6387
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6388
|
+
const requestId = this.#getNextRequestId();
|
|
6389
|
+
this.#sendCallProcedureMessage(requestId, encodedProcedureName, argsBuffer);
|
|
6390
|
+
this.#procedureCallbacks.set(requestId, (result) => {
|
|
6391
|
+
if (result.tag === "Ok") {
|
|
6392
|
+
resolve(result.value);
|
|
6393
|
+
} else {
|
|
6394
|
+
reject(result.value);
|
|
6395
|
+
}
|
|
6396
|
+
});
|
|
6397
|
+
return promise;
|
|
6398
|
+
}
|
|
6399
|
+
#callProcedureGeneric(procedureName, argsBuffer) {
|
|
6079
6400
|
const { promise, resolve, reject } = Promise.withResolvers();
|
|
6080
6401
|
const requestId = this.#getNextRequestId();
|
|
6081
6402
|
const message = ClientMessage.CallProcedure({
|
|
@@ -7016,7 +7337,7 @@ function table(opts, row, ..._) {
|
|
|
7016
7337
|
increment: 1n
|
|
7017
7338
|
});
|
|
7018
7339
|
}
|
|
7019
|
-
if (meta
|
|
7340
|
+
if (Object.prototype.hasOwnProperty.call(meta, "defaultValue")) {
|
|
7020
7341
|
const writer = new BinaryWriter(16);
|
|
7021
7342
|
builder.serialize(writer, meta.defaultValue);
|
|
7022
7343
|
defaultValues.push({
|