velocious 1.0.590 → 1.0.591
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/README.md +4 -0
- package/build/background-jobs/pooled-runner-broker-identity.js +76 -0
- package/build/background-jobs/pooled-runner-child.js +15 -5
- package/build/background-jobs/store.js +11 -14
- package/build/background-jobs/worker.js +17 -2
- package/build/database/pool/base.js +18 -1
- package/build/environment-handlers/base.js +8 -0
- package/build/environment-handlers/node.js +12 -0
- package/build/src/background-jobs/pooled-runner-broker-identity.d.ts +44 -0
- package/build/src/background-jobs/pooled-runner-broker-identity.d.ts.map +1 -0
- package/build/src/background-jobs/pooled-runner-broker-identity.js +76 -0
- package/build/src/background-jobs/pooled-runner-child.js +16 -6
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +12 -14
- package/build/src/background-jobs/worker.d.ts +6 -0
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +17 -3
- package/build/src/database/pool/base.d.ts +6 -0
- package/build/src/database/pool/base.d.ts.map +1 -1
- package/build/src/database/pool/base.js +18 -2
- package/build/src/environment-handlers/base.d.ts +12 -0
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +8 -1
- package/build/src/environment-handlers/node.d.ts +11 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +13 -1
- package/build/src/testing/shared-transaction-broker-client.d.ts +53 -0
- package/build/src/testing/shared-transaction-broker-client.d.ts.map +1 -0
- package/build/src/testing/shared-transaction-broker-client.js +105 -0
- package/build/src/testing/shared-transaction-broker.d.ts +153 -0
- package/build/src/testing/shared-transaction-broker.d.ts.map +1 -0
- package/build/src/testing/shared-transaction-broker.js +414 -0
- package/build/src/testing/shared-transaction-codec.d.ts +21 -0
- package/build/src/testing/shared-transaction-codec.d.ts.map +1 -0
- package/build/src/testing/shared-transaction-codec.js +114 -0
- package/build/src/testing/shared-transaction-connection-coordinator.d.ts +23 -0
- package/build/src/testing/shared-transaction-connection-coordinator.d.ts.map +1 -0
- package/build/src/testing/shared-transaction-connection-coordinator.js +36 -0
- package/build/src/testing/shared-transaction-proxy-driver.d.ts +42 -0
- package/build/src/testing/shared-transaction-proxy-driver.d.ts.map +1 -0
- package/build/src/testing/shared-transaction-proxy-driver.js +195 -0
- package/build/src/testing/test-runner.d.ts +20 -0
- package/build/src/testing/test-runner.d.ts.map +1 -1
- package/build/src/testing/test-runner.js +64 -3
- package/build/testing/shared-transaction-broker-client.js +107 -0
- package/build/testing/shared-transaction-broker.js +401 -0
- package/build/testing/shared-transaction-codec.js +110 -0
- package/build/testing/shared-transaction-connection-coordinator.js +38 -0
- package/build/testing/shared-transaction-proxy-driver.js +205 -0
- package/build/testing/test-runner.js +65 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -2
- package/src/background-jobs/pooled-runner-broker-identity.js +76 -0
- package/src/background-jobs/pooled-runner-child.js +15 -5
- package/src/background-jobs/store.js +11 -14
- package/src/background-jobs/worker.js +17 -2
- package/src/database/pool/base.js +18 -1
- package/src/environment-handlers/base.js +8 -0
- package/src/environment-handlers/node.js +12 -0
- package/src/testing/shared-transaction-broker-client.js +107 -0
- package/src/testing/shared-transaction-broker.js +401 -0
- package/src/testing/shared-transaction-codec.js +110 -0
- package/src/testing/shared-transaction-connection-coordinator.js +38 -0
- package/src/testing/shared-transaction-proxy-driver.js +205 -0
- package/src/testing/test-runner.js +65 -2
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { EventEmitter } from "node:events";
|
|
5
|
+
import { WebSocketServer } from "ws";
|
|
6
|
+
import { decodeBrokerValue, encodeBrokerValue } from "./shared-transaction-codec.js";
|
|
7
|
+
import { clearSharedTransactionCoordinator, setSharedTransactionCoordinator } from "./shared-transaction-connection-coordinator.js";
|
|
8
|
+
/** @typedef {{queue: Promise<void>, rootSessions: Set<import("ws").WebSocket>, lease?: {operations: Promise<void>, release: () => void, savePointName: string, socket: import("ws").WebSocket}}} ConnectionState */
|
|
9
|
+
const ALLOWED_METHODS = new Set([
|
|
10
|
+
"query",
|
|
11
|
+
"affectedRows",
|
|
12
|
+
"_queryActual",
|
|
13
|
+
"_affectedRowsActual",
|
|
14
|
+
"_startTransactionAction",
|
|
15
|
+
"_commitTransactionAction",
|
|
16
|
+
"_rollbackTransactionAction",
|
|
17
|
+
"startSavePoint",
|
|
18
|
+
"releaseSavePoint",
|
|
19
|
+
"rollbackSavePoint",
|
|
20
|
+
"getConnectionScopedValue",
|
|
21
|
+
"rootTransactionStart",
|
|
22
|
+
"rootTransactionRelease",
|
|
23
|
+
"rootTransactionRollback"
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Compares a presented capability without leaking matching prefix timing.
|
|
27
|
+
* @param {string} provided - Presented capability.
|
|
28
|
+
* @param {string} expected - Active capability.
|
|
29
|
+
* @returns {boolean} - Whether the capabilities match.
|
|
30
|
+
*/
|
|
31
|
+
function capabilityMatches(provided, expected) {
|
|
32
|
+
const providedBytes = Buffer.from(provided);
|
|
33
|
+
const expectedBytes = Buffer.from(expected);
|
|
34
|
+
return providedBytes.length === expectedBytes.length && timingSafeEqual(providedBytes, expectedBytes);
|
|
35
|
+
}
|
|
36
|
+
export default class SharedTransactionBroker extends EventEmitter {
|
|
37
|
+
/**
|
|
38
|
+
* Creates a broker around parent-owned physical connections.
|
|
39
|
+
* @param {{connections: Record<string, object>}} args - Parent-owned physical connections.
|
|
40
|
+
*/
|
|
41
|
+
constructor({ connections }) {
|
|
42
|
+
super();
|
|
43
|
+
this.connections = connections;
|
|
44
|
+
this.secret = randomBytes(32).toString("base64url");
|
|
45
|
+
this.accepting = true;
|
|
46
|
+
/** @type {Map<object, ConnectionState>} */
|
|
47
|
+
this.connectionStates = new Map();
|
|
48
|
+
/** @type {Set<import("ws").WebSocket>} */
|
|
49
|
+
this.sessions = new Set();
|
|
50
|
+
/** @type {Map<import("ws").WebSocket, Promise<void>>} */
|
|
51
|
+
this.sessionCleanup = new Map();
|
|
52
|
+
/** @type {Array<Error>} */
|
|
53
|
+
this.cleanupErrors = [];
|
|
54
|
+
/** @type {Promise<void> | undefined} */
|
|
55
|
+
this.closePromise = undefined;
|
|
56
|
+
/** @type {Map<object, (callback: () => Promise<ReturnType<typeof JSON.parse>>) => Promise<ReturnType<typeof JSON.parse>>>} */
|
|
57
|
+
this.connectionCoordinators = new Map();
|
|
58
|
+
for (const connection of new Set(Object.values(connections))) {
|
|
59
|
+
/**
|
|
60
|
+
* Serializes parent operations with child broker traffic.
|
|
61
|
+
* @param {() => Promise<unknown>} callback - Parent operation.
|
|
62
|
+
* @returns {Promise<unknown>} - Operation result.
|
|
63
|
+
*/
|
|
64
|
+
const coordinator = async (callback) => await this.serialize(this.connectionState(connection), callback);
|
|
65
|
+
this.connectionCoordinators.set(connection, coordinator);
|
|
66
|
+
setSharedTransactionCoordinator(connection, coordinator);
|
|
67
|
+
}
|
|
68
|
+
this.httpServer = createServer();
|
|
69
|
+
this.websocketServer = new WebSocketServer({ server: this.httpServer, maxPayload: 16 * 1024 * 1024 });
|
|
70
|
+
this.websocketServer.on("connection", (socket) => {
|
|
71
|
+
this.sessions.add(socket);
|
|
72
|
+
socket.once("close", () => {
|
|
73
|
+
this.sessions.delete(socket);
|
|
74
|
+
this.scheduleSessionCleanup(socket);
|
|
75
|
+
});
|
|
76
|
+
socket.on("message", (data) => void this.handleRequest(socket, `${data}`));
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Starts a broker on an ephemeral loopback port.
|
|
81
|
+
* @param {{connections: Record<string, object>}} args - Parent-owned physical connections.
|
|
82
|
+
* @returns {Promise<SharedTransactionBroker>} - Listening broker.
|
|
83
|
+
*/
|
|
84
|
+
static async start(args) {
|
|
85
|
+
const broker = new SharedTransactionBroker(args);
|
|
86
|
+
await new Promise((resolve, reject) => {
|
|
87
|
+
broker.httpServer.once("error", reject);
|
|
88
|
+
broker.httpServer.listen({ host: "127.0.0.1", port: 0 }, () => resolve(undefined));
|
|
89
|
+
});
|
|
90
|
+
return broker;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets the loopback websocket address.
|
|
94
|
+
* @returns {string} - Loopback websocket address.
|
|
95
|
+
*/
|
|
96
|
+
address() {
|
|
97
|
+
const address = this.httpServer.address();
|
|
98
|
+
if (!address || typeof address === "string")
|
|
99
|
+
throw new Error("Shared transaction broker is not listening");
|
|
100
|
+
return `ws://127.0.0.1:${address.port}`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Gets the per-attempt unguessable capability.
|
|
104
|
+
* @returns {string} - Per-attempt unguessable capability.
|
|
105
|
+
*/
|
|
106
|
+
capability() { return this.secret; }
|
|
107
|
+
/**
|
|
108
|
+
* Validates and handles one request.
|
|
109
|
+
* @param {import("ws").WebSocket} socket - Calling session.
|
|
110
|
+
* @param {string} serialized - Request JSON.
|
|
111
|
+
* @returns {Promise<void>} - Resolves after responding.
|
|
112
|
+
*/
|
|
113
|
+
async handleRequest(socket, serialized) {
|
|
114
|
+
let requestId = 0;
|
|
115
|
+
try {
|
|
116
|
+
const request = /** @type {{requestId: number, capability: string, databaseIdentifier: string, method: string, args: import("./shared-transaction-codec.js").EncodedBrokerValue}} */ (JSON.parse(serialized));
|
|
117
|
+
requestId = request.requestId;
|
|
118
|
+
if (!this.accepting)
|
|
119
|
+
throw new Error("Shared transaction broker capability has been revoked");
|
|
120
|
+
if (!capabilityMatches(request.capability, this.secret))
|
|
121
|
+
throw new Error("Unknown shared transaction broker capability");
|
|
122
|
+
const connection = this.connections[request.databaseIdentifier];
|
|
123
|
+
if (!connection)
|
|
124
|
+
throw new Error(`Unknown shared transaction database identifier: ${request.databaseIdentifier}`);
|
|
125
|
+
if (!ALLOWED_METHODS.has(request.method))
|
|
126
|
+
throw new Error(`Unsupported shared transaction broker method: ${request.method}`);
|
|
127
|
+
const args = decodeBrokerValue(request.args);
|
|
128
|
+
if (!Array.isArray(args))
|
|
129
|
+
throw new TypeError("Shared transaction broker arguments must be an array");
|
|
130
|
+
this.emit("work-queued", { connection, databaseIdentifier: request.databaseIdentifier, method: request.method });
|
|
131
|
+
const result = await this.runConnectionRequest({ connection, method: request.method, savePointName: typeof args[0] === "string" ? args[0] : undefined, socket }, async () => {
|
|
132
|
+
if (!this.accepting)
|
|
133
|
+
throw new Error("Shared transaction broker capability has been revoked");
|
|
134
|
+
if (request.method === "rootTransactionRollback") {
|
|
135
|
+
await this.rollbackRootSavePoint(connection, /** @type {string} */ (args[0]));
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
const physicalMethod = request.method === "rootTransactionStart"
|
|
139
|
+
? "startSavePoint"
|
|
140
|
+
: request.method === "rootTransactionRelease"
|
|
141
|
+
? "releaseSavePoint"
|
|
142
|
+
: request.method === "rootTransactionRollback"
|
|
143
|
+
? "rollbackSavePoint"
|
|
144
|
+
: request.method;
|
|
145
|
+
const connectionMethods = /** @type {Record<string, (...methodArgs: Array<ReturnType<typeof JSON.parse>>) => ReturnType<typeof JSON.parse>>} */ (connection);
|
|
146
|
+
const method = connectionMethods[physicalMethod];
|
|
147
|
+
if (typeof method !== "function")
|
|
148
|
+
throw new Error(`Connection does not support shared transaction method: ${request.method}`);
|
|
149
|
+
return await method.apply(connection, args);
|
|
150
|
+
});
|
|
151
|
+
if (socket.readyState === socket.OPEN)
|
|
152
|
+
socket.send(JSON.stringify({ requestId, result: encodeBrokerValue(result) }));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
156
|
+
if (socket.readyState === socket.OPEN)
|
|
157
|
+
socket.send(JSON.stringify({ requestId, error: encodeBrokerValue(normalized) }));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Gets mutable serialization state for one physical connection.
|
|
162
|
+
* @param {object} connection - Physical connection.
|
|
163
|
+
* @returns {ConnectionState} - Connection state.
|
|
164
|
+
*/
|
|
165
|
+
connectionState(connection) {
|
|
166
|
+
let state = this.connectionStates.get(connection);
|
|
167
|
+
if (!state) {
|
|
168
|
+
state = { queue: Promise.resolve(), rootSessions: new Set() };
|
|
169
|
+
this.connectionStates.set(connection, state);
|
|
170
|
+
}
|
|
171
|
+
return state;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Runs a validated request with root transaction lease semantics.
|
|
175
|
+
* @template T
|
|
176
|
+
* @param {{connection: object, method: string, savePointName: string | undefined, socket: import("ws").WebSocket}} args - Request identity.
|
|
177
|
+
* @param {() => Promise<T>} callback - Physical operation.
|
|
178
|
+
* @returns {Promise<T>} - Operation result.
|
|
179
|
+
*/
|
|
180
|
+
async runConnectionRequest({ connection, method, savePointName, socket }, callback) {
|
|
181
|
+
const state = this.connectionState(connection);
|
|
182
|
+
if (method === "rootTransactionStart") {
|
|
183
|
+
if (!savePointName)
|
|
184
|
+
throw new Error("Shared transaction broker root transaction requires a savepoint name");
|
|
185
|
+
return await this.startRootLease({ callback, savePointName, state, socket });
|
|
186
|
+
}
|
|
187
|
+
if (method === "rootTransactionRelease" || method === "rootTransactionRollback") {
|
|
188
|
+
return await this.finishRootLease({ callback, savePointName, state, socket });
|
|
189
|
+
}
|
|
190
|
+
if (state.lease?.socket === socket)
|
|
191
|
+
return await this.serializeLease(state.lease, callback);
|
|
192
|
+
return await this.serialize(state, callback);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Acquires the FIFO physical connection lease and holds the queue until end.
|
|
196
|
+
* @template T
|
|
197
|
+
* @param {{callback: () => Promise<T>, savePointName: string, state: ConnectionState, socket: import("ws").WebSocket}} args - Lease request.
|
|
198
|
+
* @returns {Promise<T>} - Root savepoint start result.
|
|
199
|
+
*/
|
|
200
|
+
async startRootLease({ callback, savePointName, state, socket }) {
|
|
201
|
+
if (state.rootSessions.has(socket))
|
|
202
|
+
throw new Error("Shared transaction broker root transaction is already active for this session");
|
|
203
|
+
state.rootSessions.add(socket);
|
|
204
|
+
const previous = state.queue;
|
|
205
|
+
/**
|
|
206
|
+
* Resolves the start response.
|
|
207
|
+
* @type {(value: T) => void}
|
|
208
|
+
*/
|
|
209
|
+
let resolveStarted = () => { };
|
|
210
|
+
/**
|
|
211
|
+
* Rejects the start response.
|
|
212
|
+
* @type {(error: Error) => void}
|
|
213
|
+
*/
|
|
214
|
+
let rejectStarted = () => { };
|
|
215
|
+
const started = new Promise((resolve, reject) => { resolveStarted = resolve; rejectStarted = reject; });
|
|
216
|
+
/**
|
|
217
|
+
* Releases the held connection queue.
|
|
218
|
+
* @type {(value?: void) => void}
|
|
219
|
+
*/
|
|
220
|
+
let release = () => { };
|
|
221
|
+
const held = new Promise((resolve) => { release = resolve; });
|
|
222
|
+
state.queue = previous.then(async () => {
|
|
223
|
+
try {
|
|
224
|
+
if (!this.accepting || socket.readyState !== socket.OPEN)
|
|
225
|
+
throw new Error("Shared transaction broker root transaction session closed before lease acquisition");
|
|
226
|
+
const result = await callback();
|
|
227
|
+
state.lease = { operations: Promise.resolve(), release, savePointName, socket };
|
|
228
|
+
resolveStarted(result);
|
|
229
|
+
await held;
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
state.rootSessions.delete(socket);
|
|
233
|
+
rejectStarted(error instanceof Error ? error : new Error(String(error)));
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return await started;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Finishes the calling session's root lease.
|
|
240
|
+
* @template T
|
|
241
|
+
* @param {{callback: () => Promise<T>, savePointName: string | undefined, state: ConnectionState, socket: import("ws").WebSocket}} args - Lease end request.
|
|
242
|
+
* @returns {Promise<T>} - Savepoint end result.
|
|
243
|
+
*/
|
|
244
|
+
async finishRootLease({ callback, savePointName, state, socket }) {
|
|
245
|
+
const lease = state.lease;
|
|
246
|
+
if (!lease || lease.socket !== socket)
|
|
247
|
+
throw new Error("Shared transaction broker session does not own the root transaction lease");
|
|
248
|
+
if (savePointName !== lease.savePointName)
|
|
249
|
+
throw new Error("Shared transaction broker root transaction savepoint does not match its lease");
|
|
250
|
+
try {
|
|
251
|
+
return await this.serializeLease(lease, callback);
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
state.lease = undefined;
|
|
255
|
+
state.rootSessions.delete(socket);
|
|
256
|
+
lease.release();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Serializes operations belonging to the active lease holder.
|
|
261
|
+
* @template T
|
|
262
|
+
* @param {{operations: Promise<void>}} lease - Active lease.
|
|
263
|
+
* @param {() => Promise<T>} callback - Operation.
|
|
264
|
+
* @returns {Promise<T>} - Result.
|
|
265
|
+
*/
|
|
266
|
+
async serializeLease(lease, callback) {
|
|
267
|
+
const previous = lease.operations;
|
|
268
|
+
/**
|
|
269
|
+
* Releases the holder operation queue.
|
|
270
|
+
* @type {(value?: void) => void}
|
|
271
|
+
*/
|
|
272
|
+
let release = () => { };
|
|
273
|
+
const current = new Promise((resolve) => { release = resolve; });
|
|
274
|
+
lease.operations = previous.then(() => current);
|
|
275
|
+
await previous;
|
|
276
|
+
try {
|
|
277
|
+
return await callback();
|
|
278
|
+
}
|
|
279
|
+
finally {
|
|
280
|
+
release();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Rolls back leases abandoned by a disconnected session.
|
|
285
|
+
* @param {import("ws").WebSocket} socket - Disconnected session.
|
|
286
|
+
* @returns {Promise<void>} - Resolves after all owned leases release.
|
|
287
|
+
*/
|
|
288
|
+
async releaseDisconnectedLeases(socket) {
|
|
289
|
+
/** @type {Array<Error>} */
|
|
290
|
+
const errors = [];
|
|
291
|
+
for (const [connection, state] of this.connectionStates) {
|
|
292
|
+
const lease = state.lease;
|
|
293
|
+
if (!lease || lease.socket !== socket)
|
|
294
|
+
continue;
|
|
295
|
+
try {
|
|
296
|
+
await this.serializeLease(lease, async () => {
|
|
297
|
+
await this.rollbackRootSavePoint(connection, lease.savePointName);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
state.lease = undefined;
|
|
305
|
+
state.rootSessions.delete(socket);
|
|
306
|
+
lease.release();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (errors.length > 0) {
|
|
310
|
+
throw new AggregateError(errors, `Shared transaction broker lease cleanup failed: ${errors.map((error) => error.message).join("; ")}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Tracks detached socket cleanup and records its failure for close().
|
|
315
|
+
* @param {import("ws").WebSocket} socket - Closed session.
|
|
316
|
+
* @returns {Promise<void>} - Settled tracked cleanup.
|
|
317
|
+
*/
|
|
318
|
+
scheduleSessionCleanup(socket) {
|
|
319
|
+
const existing = this.sessionCleanup.get(socket);
|
|
320
|
+
if (existing)
|
|
321
|
+
return existing;
|
|
322
|
+
const cleanup = this.releaseDisconnectedLeases(socket)
|
|
323
|
+
.catch((error) => {
|
|
324
|
+
this.cleanupErrors.push(error instanceof Error ? error : new Error(String(error)));
|
|
325
|
+
})
|
|
326
|
+
.finally(() => this.sessionCleanup.delete(socket));
|
|
327
|
+
this.sessionCleanup.set(socket, cleanup);
|
|
328
|
+
return cleanup;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Rolls back and removes a root savepoint so it cannot remain beneath the next lease.
|
|
332
|
+
* @param {object} connection - Parent physical connection.
|
|
333
|
+
* @param {string} savePointName - Root savepoint name.
|
|
334
|
+
* @returns {Promise<void>} - Resolves after rollback and release.
|
|
335
|
+
*/
|
|
336
|
+
async rollbackRootSavePoint(connection, savePointName) {
|
|
337
|
+
const methods = /** @type {{releaseSavePoint: (name: string) => Promise<void>, rollbackSavePoint: (name: string) => Promise<void>}} */ (connection);
|
|
338
|
+
/** @type {Array<Error>} */
|
|
339
|
+
const errors = [];
|
|
340
|
+
try {
|
|
341
|
+
await methods.rollbackSavePoint(savePointName);
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
await methods.releaseSavePoint(savePointName);
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
351
|
+
}
|
|
352
|
+
if (errors.length > 0) {
|
|
353
|
+
throw new AggregateError(errors, `Shared transaction broker could not clean root savepoint ${savePointName}: ${errors.map((error) => error.message).join("; ")}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Serializes ordinary non-holder work through the connection FIFO.
|
|
358
|
+
* @template T
|
|
359
|
+
* @param {ConnectionState} state - Connection state.
|
|
360
|
+
* @param {() => Promise<T>} callback - Work.
|
|
361
|
+
* @returns {Promise<T>} - Work result.
|
|
362
|
+
*/
|
|
363
|
+
async serialize(state, callback) {
|
|
364
|
+
const previous = state.queue;
|
|
365
|
+
/**
|
|
366
|
+
* Resolves the current queue entry.
|
|
367
|
+
* @type {(value?: void) => void}
|
|
368
|
+
*/
|
|
369
|
+
let release = () => { };
|
|
370
|
+
const current = new Promise((resolve) => { release = resolve; });
|
|
371
|
+
const queued = previous.then(() => current);
|
|
372
|
+
state.queue = queued;
|
|
373
|
+
await previous;
|
|
374
|
+
try {
|
|
375
|
+
return await callback();
|
|
376
|
+
}
|
|
377
|
+
finally {
|
|
378
|
+
release();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Stops admission, revokes capability, rejects clients, and drains active work.
|
|
383
|
+
* @returns {Promise<void>} - Resolves after transport shutdown.
|
|
384
|
+
*/
|
|
385
|
+
async close() {
|
|
386
|
+
if (this.closePromise)
|
|
387
|
+
return await this.closePromise;
|
|
388
|
+
this.closePromise = this.closeTransport();
|
|
389
|
+
return await this.closePromise;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Performs deterministic transport shutdown and reports cleanup failures last.
|
|
393
|
+
* @returns {Promise<void>} - Resolves after shutdown or rejects with cleanup errors.
|
|
394
|
+
*/
|
|
395
|
+
async closeTransport() {
|
|
396
|
+
this.accepting = false;
|
|
397
|
+
this.secret = randomBytes(32).toString("base64url");
|
|
398
|
+
const closingSessions = Array.from(this.sessions);
|
|
399
|
+
await Promise.all(closingSessions.map(async (socket) => await this.scheduleSessionCleanup(socket)));
|
|
400
|
+
for (const socket of closingSessions)
|
|
401
|
+
socket.close(1001, "Shared transaction broker closed");
|
|
402
|
+
await Promise.allSettled(Array.from(this.connectionStates.values()).map((state) => state.queue));
|
|
403
|
+
await new Promise((resolve) => this.websocketServer.close(() => resolve(undefined)));
|
|
404
|
+
await new Promise((resolve) => this.httpServer.close(() => resolve(undefined)));
|
|
405
|
+
await Promise.all(Array.from(this.sessionCleanup.values()));
|
|
406
|
+
for (const [connection, coordinator] of this.connectionCoordinators) {
|
|
407
|
+
clearSharedTransactionCoordinator(connection, coordinator);
|
|
408
|
+
}
|
|
409
|
+
if (this.cleanupErrors.length > 0) {
|
|
410
|
+
throw new AggregateError(this.cleanupErrors, `Shared transaction broker cleanup failed: ${this.cleanupErrors.map((error) => error.message).join("; ")}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLXRyYW5zYWN0aW9uLWJyb2tlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZXN0aW5nL3NoYXJlZC10cmFuc2FjdGlvbi1icm9rZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBRSxXQUFXLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzFELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUMxQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sSUFBSSxDQUFBO0FBQ3BDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLCtCQUErQixDQUFBO0FBQ3BGLE9BQU8sRUFBQyxpQ0FBaUMsRUFBRSwrQkFBK0IsRUFBQyxNQUFNLGdEQUFnRCxDQUFBO0FBRWpJLG9OQUFvTjtBQUVwTixNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUM5QixPQUFPO0lBQ1AsY0FBYztJQUNkLGNBQWM7SUFDZCxxQkFBcUI7SUFDckIseUJBQXlCO0lBQ3pCLDBCQUEwQjtJQUMxQiw0QkFBNEI7SUFDNUIsZ0JBQWdCO0lBQ2hCLGtCQUFrQjtJQUNsQixtQkFBbUI7SUFDbkIsMEJBQTBCO0lBQzFCLHNCQUFzQjtJQUN0Qix3QkFBd0I7SUFDeEIseUJBQXlCO0NBQzFCLENBQUMsQ0FBQTtBQUVGOzs7OztHQUtHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxRQUFRLEVBQUUsUUFBUTtJQUMzQyxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQzNDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDM0MsT0FBTyxhQUFhLENBQUMsTUFBTSxLQUFLLGFBQWEsQ0FBQyxNQUFNLElB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RyxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3BGLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDL0UsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUE7UUFDM0QsS0FBSyxNQUFNLENBQUMsVUFBVSxFQUFFLFdBQVcsQ0FBQyxJQUFJLElBQUksQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1lBQ3BFLGlDQUFpQyxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQTtRQUM1RCxDQUFDO1FBQ0QsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsNkNBQTZDLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUMxSixDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7IHJhbmRvbUJ5dGVzLCB0aW1pbmdTYWZlRXF1YWwgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSBcIm5vZGU6aHR0cFwiXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwibm9kZTpldmVudHNcIlxuaW1wb3J0IHsgV2ViU29ja2V0U2VydmVyIH0gZnJvbSBcIndzXCJcbmltcG9ydCB7IGRlY29kZUJyb2tlclZhbHVlLCBlbmNvZGVCcm9rZXJWYWx1ZSB9IGZyb20gXCIuL3NoYXJlZC10cmFuc2FjdGlvbi1jb2RlYy5qc1wiXG5pbXBvcnQge2NsZWFyU2hhcmVkVHJhbnNhY3Rpb25Db29yZGluYXRvciwgc2V0U2hhcmVkVHJhbnNhY3Rpb25Db29yZGluYXRvcn0gZnJvbSBcIi4vc2hhcmVkLXRyYW5zYWN0aW9uLWNvbm5lY3Rpb24tY29vcmRpbmF0b3IuanNcIlxuXG4vKiogQHR5cGVkZWYge3txdWV1ZTogUHJvbWlzZTx2b2lkPiwgcm9vdFNlc3Npb25zOiBTZXQ8aW1wb3J0KFwid3NcIikuV2ViU29ja2V0PiwgbGVhc2U/OiB7b3BlcmF0aW9uczogUHJvbWlzZTx2b2lkPiwgcmVsZWFzZTogKCkgPT4gdm9pZCwgc2F2ZVBvaW50TmFtZTogc3RyaW5nLCBzb2NrZXQ6IGltcG9ydChcIndzXCIpLldlYlNvY2tldH19fSBDb25uZWN0aW9uU3RhdGUgKi9cblxuY29uc3QgQUxMT1dFRF9NRVRIT0RTID0gbmV3IFNldChbXG4gIFwicXVlcnlcIixcbiAgXCJhZmZlY3RlZFJvd3NcIixcbiAgXCJfcXVlcnlBY3R1YWxcIixcbiAgXCJfYWZmZWN0ZWRSb3dzQWN0dWFsXCIsXG4gIFwiX3N0YXJ0VHJhbnNhY3Rpb25BY3Rpb25cIixcbiAgXCJfY29tbWl0VHJhbnNhY3Rpb25BY3Rpb25cIixcbiAgXCJfcm9sbGJhY2tUcmFuc2FjdGlvbkFjdGlvblwiLFxuICBcInN0YXJ0U2F2ZVBvaW50XCIsXG4gIFwicmVsZWFzZVNhdmVQb2ludFwiLFxuICBcInJvbGxiYWNrU2F2ZVBvaW50XCIsXG4gIFwiZ2V0Q29ubmVjdGlvblNjb3BlZFZhbHVlXCIsXG4gIFwicm9vdFRyYW5zYWN0aW9uU3RhcnRcIixcbiAgXCJyb290VHJhbnNhY3Rpb25SZWxlYXNlXCIsXG4gIFwicm9vdFRyYW5zYWN0aW9uUm9sbGJhY2tcIlxuXSlcblxuLyoqXG4gKiBDb21wYXJlcyBhIHByZXNlbnRlZCBjYXBhYmlsaXR5IHdpdGhvdXQgbGVha2luZyBtYXRjaGluZyBwcmVmaXggdGltaW5nLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3ZpZGVkIC0gUHJlc2VudGVkIGNhcGFiaWxpdHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZXhwZWN0ZWQgLSBBY3RpdmUgY2FwYWJpbGl0eS5cbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgdGhlIGNhcGFiaWxpdGllcyBtYXRjaC5cbiAqL1xuZnVuY3Rpb24gY2FwYWJpbGl0eU1hdGNoZXMocHJvdmlkZWQsIGV4cGVjdGVkKSB7XG4gIGNvbnN0IHByb3ZpZGVkQnl0ZXMgPSBCdWZmZXIuZnJvbShwcm92aWRlZClcbiAgY29uc3QgZXhwZWN0ZWRCeXRlcyA9IEJ1ZmZlci5mcm9tKGV4cGVjdGVkKVxuICByZXR1cm4gcHJvdmlkZWRCeXRlcy5sZW5ndGggPT09IGV4cGVjdGVkQnl0ZXMubGVuZ3RoICYmIHRpbWluZ1NhZmVFcXVhbChwcm92aWRlZEJ5dGVzLCBleHBlY3RlZEJ5dGVzKVxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTaGFyZWRUcmFuc2FjdGlvbkJyb2tlciBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgYnJva2VyIGFyb3VuZCBwYXJlbnQtb3duZWQgcGh5c2ljYWwgY29ubmVjdGlvbnMuXG4gICAqIEBwYXJhbSB7e2Nvbm5lY3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBvYmplY3Q+fX0gYXJncyAtIFBhcmVudC1vd25lZCBwaHlzaWNhbCBjb25uZWN0aW9ucy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25uZWN0aW9uc30pIHtcbiAgICBzdXBlcigpXG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IGNvbm5lY3Rpb25zXG4gICAgdGhpcy5zZWNyZXQgPSByYW5kb21CeXRlcygzMikudG9TdHJpbmcoXCJiYXNlNjR1cmxcIilcbiAgICB0aGlzLmFjY2VwdGluZyA9IHRydWVcbiAgICAvKiogQHR5cGUge01hcDxvYmplY3QsIENvbm5lY3Rpb25TdGF0ZT59ICovXG4gICAgdGhpcy5jb25uZWN0aW9uU3RhdGVzID0gbmV3IE1hcCgpXG4gICAgLyoqIEB0eXBlIHtTZXQ8aW1wb3J0KFwid3NcIikuV2ViU29ja2V0Pn0gKi9cbiAgICB0aGlzLnNlc3Npb25zID0gbmV3IFNldCgpXG4gICAgLyoqIEB0eXBlIHtNYXA8aW1wb3J0KFwid3NcIikuV2ViU29ja2V0LCBQcm9taXNlPHZvaWQ+Pn0gKi9cbiAgICB0aGlzLnNlc3Npb25DbGVhbnVwID0gbmV3IE1hcCgpXG4gICAgLyoqIEB0eXBlIHtBcnJheTxFcnJvcj59ICovXG4gICAgdGhpcy5jbGVhbnVwRXJyb3JzID0gW11cbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCB1bmRlZmluZWR9ICovXG4gICAgdGhpcy5jbG9zZVByb21pc2UgPSB1bmRlZmluZWRcbiAgICAvKiogQHR5cGUge01hcDxvYmplY3QsIChjYWxsYmFjazogKCkgPT4gUHJvbWlzZTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj4pID0+IFByb21pc2U8UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4+Pn0gKi9cbiAgICB0aGlzLmNvbm5lY3Rpb25Db29yZGluYXRvcnMgPSBuZXcgTWFwKClcbiAgICBmb3IgKGNvbnN0IGNvbm5lY3Rpb24gb2YgbmV3IFNldChPYmplY3QudmFsdWVzKGNvbm5lY3Rpb25zKSkpIHtcbiAgICAgIC8qKlxuICAgICAgICogU2VyaWFsaXplcyBwYXJlbnQgb3BlcmF0aW9ucyB3aXRoIGNoaWxkIGJyb2tlciB0cmFmZmljLlxuICAgICAgICogQHBhcmFtIHsoKSA9PiBQcm9taXNlPHVua25vd24+fSBjYWxsYmFjayAtIFBhcmVudCBvcGVyYXRpb24uXG4gICAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gLSBPcGVyYXRpb24gcmVzdWx0LlxuICAgICAgICovXG4gICAgICBjb25zdCBjb29yZGluYXRvciA9IGFzeW5jIChjYWxsYmFjaykgPT4gYXdhaXQgdGhpcy5zZXJpYWxpemUodGhpcy5jb25uZWN0aW9uU3RhdGUoY29ubmVjdGlvbiksIGNhbGxiYWNrKVxuICAgICAgdGhpcy5jb25uZWN0aW9uQ29vcmRpbmF0b3JzLnNldChjb25uZWN0aW9uLCBjb29yZGluYXRvcilcbiAgICAgIHNldFNoYXJlZFRyYW5zYWN0aW9uQ29vcmRpbmF0b3IoY29ubmVjdGlvbiwgY29vcmRpbmF0b3IpXG4gICAgfVxuICAgIHRoaXMuaHR0cFNlcnZlciA9IGNyZWF0ZVNlcnZlcigpXG4gICAgdGhpcy53ZWJzb2NrZXRTZXJ2ZXIgPSBuZXcgV2ViU29ja2V0U2VydmVyKHtzZXJ2ZXI6IHRoaXMuaHR0cFNlcnZlciwgbWF4UGF5bG9hZDogMTYgKiAxMDI0ICogMTAyNH0pXG4gICAgdGhpcy53ZWJzb2NrZXRTZXJ2ZXIub24oXCJjb25uZWN0aW9uXCIsIChzb2NrZXQpID0+IHtcbiAgICAgIHRoaXMuc2Vzc2lvbnMuYWRkKHNvY2tldClcbiAgICAgIHNvY2tldC5vbmNlKFwiY2xvc2VcIiwgKCkgPT4ge1xuICAgICAgICB0aGlzLnNlc3Npb25zLmRlbGV0ZShzb2NrZXQpXG4gICAgICAgIHRoaXMuc2NoZWR1bGVTZXNzaW9uQ2xlYW51cChzb2NrZXQpXG4gICAgICB9KVxuICAgICAgc29ja2V0Lm9uKFwibWVzc2FnZVwiLCAoZGF0YSkgPT4gdm9pZCB0aGlzLmhhbmRsZVJlcXVlc3Qoc29ja2V0LCBgJHtkYXRhfWApKVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogU3RhcnRzIGEgYnJva2VyIG9uIGFuIGVwaGVtZXJhbCBsb29wYmFjayBwb3J0LlxuICAgKiBAcGFyYW0ge3tjb25uZWN0aW9uczogUmVjb3JkPHN0cmluZywgb2JqZWN0Pn19IGFyZ3MgLSBQYXJlbnQtb3duZWQgcGh5c2ljYWwgY29ubmVjdGlvbnMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFNoYXJlZFRyYW5zYWN0aW9uQnJva2VyPn0gLSBMaXN0ZW5pbmcgYnJva2VyLlxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHN0YXJ0KGFyZ3MpIHtcbiAgICBjb25zdCBicm9rZXIgPSBuZXcgU2hhcmVkVHJhbnNhY3Rpb25Ccm9rZXIoYXJncylcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBicm9rZXIuaHR0cFNlcnZlci5vbmNlKFwiZXJyb3JcIiwgcmVqZWN0KVxuICAgICAgYnJva2VyLmh0dHBTZXJ2ZXIubGlzdGVuKHtob3N0OiBcIjEyNy4wLjAuMVwiLCBwb3J0OiAwfSwgKCkgPT4gcmVzb2x2ZSh1bmRlZmluZWQpKVxuICAgIH0pXG4gICAgcmV0dXJuIGJyb2tlclxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGxvb3BiYWNrIHdlYnNvY2tldCBhZGRyZXNzLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIExvb3BiYWNrIHdlYnNvY2tldCBhZGRyZXNzLlxuICAgKi9cbiAgYWRkcmVzcygpIHtcbiAgICBjb25zdCBhZGRyZXNzID0gdGhpcy5odHRwU2VydmVyLmFkZHJlc3MoKVxuICAgIGlmICghYWRkcmVzcyB8fCB0eXBlb2YgYWRkcmVzcyA9PT0gXCJzdHJpbmdcIikgdGhyb3cgbmV3IEVycm9yKFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBpcyBub3QgbGlzdGVuaW5nXCIpXG4gICAgcmV0dXJuIGB3czovLzEyNy4wLjAuMToke2FkZHJlc3MucG9ydH1gXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgcGVyLWF0dGVtcHQgdW5ndWVzc2FibGUgY2FwYWJpbGl0eS5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBQZXItYXR0ZW1wdCB1bmd1ZXNzYWJsZSBjYXBhYmlsaXR5LlxuICAgKi9cbiAgY2FwYWJpbGl0eSgpIHsgcmV0dXJuIHRoaXMuc2VjcmV0IH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGFuZCBoYW5kbGVzIG9uZSByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIndzXCIpLldlYlNvY2tldH0gc29ja2V0IC0gQ2FsbGluZyBzZXNzaW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VyaWFsaXplZCAtIFJlcXVlc3QgSlNPTi5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgcmVzcG9uZGluZy5cbiAgICovXG4gIGFzeW5jIGhhbmRsZVJlcXVlc3Qoc29ja2V0LCBzZXJpYWxpemVkKSB7XG4gICAgbGV0IHJlcXVlc3RJZCA9IDBcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVxdWVzdCA9IC8qKiBAdHlwZSB7e3JlcXVlc3RJZDogbnVtYmVyLCBjYXBhYmlsaXR5OiBzdHJpbmcsIGRhdGFiYXNlSWRlbnRpZmllcjogc3RyaW5nLCBtZXRob2Q6IHN0cmluZywgYXJnczogaW1wb3J0KFwiLi9zaGFyZWQtdHJhbnNhY3Rpb24tY29kZWMuanNcIikuRW5jb2RlZEJyb2tlclZhbHVlfX0gKi8gKEpTT04ucGFyc2Uoc2VyaWFsaXplZCkpXG4gICAgICByZXF1ZXN0SWQgPSByZXF1ZXN0LnJlcXVlc3RJZFxuICAgICAgaWYgKCF0aGlzLmFjY2VwdGluZykgdGhyb3cgbmV3IEVycm9yKFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBjYXBhYmlsaXR5IGhhcyBiZWVuIHJldm9rZWRcIilcbiAgICAgIGlmICghY2FwYWJpbGl0eU1hdGNoZXMocmVxdWVzdC5jYXBhYmlsaXR5LCB0aGlzLnNlY3JldCkpIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gc2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBjYXBhYmlsaXR5XCIpXG4gICAgICBjb25zdCBjb25uZWN0aW9uID0gdGhpcy5jb25uZWN0aW9uc1tyZXF1ZXN0LmRhdGFiYXNlSWRlbnRpZmllcl1cbiAgICAgIGlmICghY29ubmVjdGlvbikgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIHNoYXJlZCB0cmFuc2FjdGlvbiBkYXRhYmFzZSBpZGVudGlmaWVyOiAke3JlcXVlc3QuZGF0YWJhc2VJZGVudGlmaWVyfWApXG4gICAgICBpZiAoIUFMTE9XRURfTUVUSE9EUy5oYXMocmVxdWVzdC5tZXRob2QpKSB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIHNoYXJlZCB0cmFuc2FjdGlvbiBicm9rZXIgbWV0aG9kOiAke3JlcXVlc3QubWV0aG9kfWApXG4gICAgICBjb25zdCBhcmdzID0gZGVjb2RlQnJva2VyVmFsdWUocmVxdWVzdC5hcmdzKVxuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGFyZ3MpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBhcmd1bWVudHMgbXVzdCBiZSBhbiBhcnJheVwiKVxuICAgICAgdGhpcy5lbWl0KFwid29yay1xdWV1ZWRcIiwge2Nvbm5lY3Rpb24sIGRhdGFiYXNlSWRlbnRpZmllcjogcmVxdWVzdC5kYXRhYmFzZUlkZW50aWZpZXIsIG1ldGhvZDogcmVxdWVzdC5tZXRob2R9KVxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW5Db25uZWN0aW9uUmVxdWVzdCh7Y29ubmVjdGlvbiwgbWV0aG9kOiByZXF1ZXN0Lm1ldGhvZCwgc2F2ZVBvaW50TmFtZTogdHlwZW9mIGFyZ3NbMF0gPT09IFwic3RyaW5nXCIgPyBhcmdzWzBdIDogdW5kZWZpbmVkLCBzb2NrZXR9LCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmICghdGhpcy5hY2NlcHRpbmcpIHRocm93IG5ldyBFcnJvcihcIlNoYXJlZCB0cmFuc2FjdGlvbiBicm9rZXIgY2FwYWJpbGl0eSBoYXMgYmVlbiByZXZva2VkXCIpXG4gICAgICAgIGlmIChyZXF1ZXN0Lm1ldGhvZCA9PT0gXCJyb290VHJhbnNhY3Rpb25Sb2xsYmFja1wiKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5yb2xsYmFja1Jvb3RTYXZlUG9pbnQoY29ubmVjdGlvbiwgLyoqIEB0eXBlIHtzdHJpbmd9ICovIChhcmdzWzBdKSlcbiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcGh5c2ljYWxNZXRob2QgPSByZXF1ZXN0Lm1ldGhvZCA9PT0gXCJyb290VHJhbnNhY3Rpb25TdGFydFwiXG4gICAgICAgICAgPyBcInN0YXJ0U2F2ZVBvaW50XCJcbiAgICAgICAgICA6IHJlcXVlc3QubWV0aG9kID09PSBcInJvb3RUcmFuc2FjdGlvblJlbGVhc2VcIlxuICAgICAgICAgICAgPyBcInJlbGVhc2VTYXZlUG9pbnRcIlxuICAgICAgICAgICAgOiByZXF1ZXN0Lm1ldGhvZCA9PT0gXCJyb290VHJhbnNhY3Rpb25Sb2xsYmFja1wiXG4gICAgICAgICAgICAgID8gXCJyb2xsYmFja1NhdmVQb2ludFwiXG4gICAgICAgICAgICAgIDogcmVxdWVzdC5tZXRob2RcbiAgICAgICAgY29uc3QgY29ubmVjdGlvbk1ldGhvZHMgPSAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsICguLi5tZXRob2RBcmdzOiBBcnJheTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj4pID0+IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gKi8gKGNvbm5lY3Rpb24pXG4gICAgICAgIGNvbnN0IG1ldGhvZCA9IGNvbm5lY3Rpb25NZXRob2RzW3BoeXNpY2FsTWV0aG9kXVxuICAgICAgICBpZiAodHlwZW9mIG1ldGhvZCAhPT0gXCJmdW5jdGlvblwiKSB0aHJvdyBuZXcgRXJyb3IoYENvbm5lY3Rpb24gZG9lcyBub3Qgc3VwcG9ydCBzaGFyZWQgdHJhbnNhY3Rpb24gbWV0aG9kOiAke3JlcXVlc3QubWV0aG9kfWApXG4gICAgICAgIHJldHVybiBhd2FpdCBtZXRob2QuYXBwbHkoY29ubmVjdGlvbiwgYXJncylcbiAgICAgIH0pXG4gICAgICBpZiAoc29ja2V0LnJlYWR5U3RhdGUgPT09IHNvY2tldC5PUEVOKSBzb2NrZXQuc2VuZChKU09OLnN0cmluZ2lmeSh7cmVxdWVzdElkLCByZXN1bHQ6IGVuY29kZUJyb2tlclZhbHVlKHJlc3VsdCl9KSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKVxuICAgICAgaWYgKHNvY2tldC5yZWFkeVN0YXRlID09PSBzb2NrZXQuT1BFTikgc29ja2V0LnNlbmQoSlNPTi5zdHJpbmdpZnkoe3JlcXVlc3RJZCwgZXJyb3I6IGVuY29kZUJyb2tlclZhbHVlKG5vcm1hbGl6ZWQpfSkpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgbXV0YWJsZSBzZXJpYWxpemF0aW9uIHN0YXRlIGZvciBvbmUgcGh5c2ljYWwgY29ubmVjdGlvbi5cbiAgICogQHBhcmFtIHtvYmplY3R9IGNvbm5lY3Rpb24gLSBQaHlzaWNhbCBjb25uZWN0aW9uLlxuICAgKiBAcmV0dXJucyB7Q29ubmVjdGlvblN0YXRlfSAtIENvbm5lY3Rpb24gc3RhdGUuXG4gICAqL1xuICBjb25uZWN0aW9uU3RhdGUoY29ubmVjdGlvbikge1xuICAgIGxldCBzdGF0ZSA9IHRoaXMuY29ubmVjdGlvblN0YXRlcy5nZXQoY29ubmVjdGlvbilcbiAgICBpZiAoIXN0YXRlKSB7XG4gICAgICBzdGF0ZSA9IHtxdWV1ZTogUHJvbWlzZS5yZXNvbHZlKCksIHJvb3RTZXNzaW9uczogbmV3IFNldCgpfVxuICAgICAgdGhpcy5jb25uZWN0aW9uU3RhdGVzLnNldChjb25uZWN0aW9uLCBzdGF0ZSlcbiAgICB9XG4gICAgcmV0dXJuIHN0YXRlXG4gIH1cblxuICAvKipcbiAgICogUnVucyBhIHZhbGlkYXRlZCByZXF1ZXN0IHdpdGggcm9vdCB0cmFuc2FjdGlvbiBsZWFzZSBzZW1hbnRpY3MuXG4gICAqIEB0ZW1wbGF0ZSBUXG4gICAqIEBwYXJhbSB7e2Nvbm5lY3Rpb246IG9iamVjdCwgbWV0aG9kOiBzdHJpbmcsIHNhdmVQb2ludE5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZCwgc29ja2V0OiBpbXBvcnQoXCJ3c1wiKS5XZWJTb2NrZXR9fSBhcmdzIC0gUmVxdWVzdCBpZGVudGl0eS5cbiAgICogQHBhcmFtIHsoKSA9PiBQcm9taXNlPFQ+fSBjYWxsYmFjayAtIFBoeXNpY2FsIG9wZXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8VD59IC0gT3BlcmF0aW9uIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIHJ1bkNvbm5lY3Rpb25SZXF1ZXN0KHtjb25uZWN0aW9uLCBtZXRob2QsIHNhdmVQb2ludE5hbWUsIHNvY2tldH0sIGNhbGxiYWNrKSB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLmNvbm5lY3Rpb25TdGF0ZShjb25uZWN0aW9uKVxuICAgIGlmIChtZXRob2QgPT09IFwicm9vdFRyYW5zYWN0aW9uU3RhcnRcIikge1xuICAgICAgaWYgKCFzYXZlUG9pbnROYW1lKSB0aHJvdyBuZXcgRXJyb3IoXCJTaGFyZWQgdHJhbnNhY3Rpb24gYnJva2VyIHJvb3QgdHJhbnNhY3Rpb24gcmVxdWlyZXMgYSBzYXZlcG9pbnQgbmFtZVwiKVxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc3RhcnRSb290TGVhc2Uoe2NhbGxiYWNrLCBzYXZlUG9pbnROYW1lLCBzdGF0ZSwgc29ja2V0fSlcbiAgICB9XG4gICAgaWYgKG1ldGhvZCA9PT0gXCJyb290VHJhbnNhY3Rpb25SZWxlYXNlXCIgfHwgbWV0aG9kID09PSBcInJvb3RUcmFuc2FjdGlvblJvbGxiYWNrXCIpIHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmZpbmlzaFJvb3RMZWFzZSh7Y2FsbGJhY2ssIHNhdmVQb2ludE5hbWUsIHN0YXRlLCBzb2NrZXR9KVxuICAgIH1cbiAgICBpZiAoc3RhdGUubGVhc2U/LnNvY2tldCA9PT0gc29ja2V0KSByZXR1cm4gYXdhaXQgdGhpcy5zZXJpYWxpemVMZWFzZShzdGF0ZS5sZWFzZSwgY2FsbGJhY2spXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VyaWFsaXplKHN0YXRlLCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3F1aXJlcyB0aGUgRklGTyBwaHlzaWNhbCBjb25uZWN0aW9uIGxlYXNlIGFuZCBob2xkcyB0aGUgcXVldWUgdW50aWwgZW5kLlxuICAgKiBAdGVtcGxhdGUgVFxuICAgKiBAcGFyYW0ge3tjYWxsYmFjazogKCkgPT4gUHJvbWlzZTxUPiwgc2F2ZVBvaW50TmFtZTogc3RyaW5nLCBzdGF0ZTogQ29ubmVjdGlvblN0YXRlLCBzb2NrZXQ6IGltcG9ydChcIndzXCIpLldlYlNvY2tldH19IGFyZ3MgLSBMZWFzZSByZXF1ZXN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn0gLSBSb290IHNhdmVwb2ludCBzdGFydCByZXN1bHQuXG4gICAqL1xuICBhc3luYyBzdGFydFJvb3RMZWFzZSh7Y2FsbGJhY2ssIHNhdmVQb2ludE5hbWUsIHN0YXRlLCBzb2NrZXR9KSB7XG4gICAgaWYgKHN0YXRlLnJvb3RTZXNzaW9ucy5oYXMoc29ja2V0KSkgdGhyb3cgbmV3IEVycm9yKFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciByb290IHRyYW5zYWN0aW9uIGlzIGFscmVhZHkgYWN0aXZlIGZvciB0aGlzIHNlc3Npb25cIilcbiAgICBzdGF0ZS5yb290U2Vzc2lvbnMuYWRkKHNvY2tldClcbiAgICBjb25zdCBwcmV2aW91cyA9IHN0YXRlLnF1ZXVlXG4gICAgLyoqXG4gICAgICogUmVzb2x2ZXMgdGhlIHN0YXJ0IHJlc3BvbnNlLlxuICAgICAqIEB0eXBlIHsodmFsdWU6IFQpID0+IHZvaWR9XG4gICAgICovXG4gICAgbGV0IHJlc29sdmVTdGFydGVkID0gKCkgPT4ge31cbiAgICAvKipcbiAgICAgKiBSZWplY3RzIHRoZSBzdGFydCByZXNwb25zZS5cbiAgICAgKiBAdHlwZSB7KGVycm9yOiBFcnJvcikgPT4gdm9pZH1cbiAgICAgKi9cbiAgICBsZXQgcmVqZWN0U3RhcnRlZCA9ICgpID0+IHt9XG4gICAgY29uc3Qgc3RhcnRlZCA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHsgcmVzb2x2ZVN0YXJ0ZWQgPSByZXNvbHZlOyByZWplY3RTdGFydGVkID0gcmVqZWN0IH0pXG4gICAgLyoqXG4gICAgICogUmVsZWFzZXMgdGhlIGhlbGQgY29ubmVjdGlvbiBxdWV1ZS5cbiAgICAgKiBAdHlwZSB7KHZhbHVlPzogdm9pZCkgPT4gdm9pZH1cbiAgICAgKi9cbiAgICBsZXQgcmVsZWFzZSA9ICgpID0+IHt9XG4gICAgY29uc3QgaGVsZCA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7IHJlbGVhc2UgPSByZXNvbHZlIH0pXG5cbiAgICBzdGF0ZS5xdWV1ZSA9IHByZXZpb3VzLnRoZW4oYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCF0aGlzLmFjY2VwdGluZyB8fCBzb2NrZXQucmVhZHlTdGF0ZSAhPT0gc29ja2V0Lk9QRU4pIHRocm93IG5ldyBFcnJvcihcIlNoYXJlZCB0cmFuc2FjdGlvbiBicm9rZXIgcm9vdCB0cmFuc2FjdGlvbiBzZXNzaW9uIGNsb3NlZCBiZWZvcmUgbGVhc2UgYWNxdWlzaXRpb25cIilcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2FsbGJhY2soKVxuICAgICAgICBzdGF0ZS5sZWFzZSA9IHtvcGVyYXRpb25zOiBQcm9taXNlLnJlc29sdmUoKSwgcmVsZWFzZSwgc2F2ZVBvaW50TmFtZSwgc29ja2V0fVxuICAgICAgICByZXNvbHZlU3RhcnRlZChyZXN1bHQpXG4gICAgICAgIGF3YWl0IGhlbGRcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHN0YXRlLnJvb3RTZXNzaW9ucy5kZWxldGUoc29ja2V0KVxuICAgICAgICByZWplY3RTdGFydGVkKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSlcbiAgICAgIH1cbiAgICB9KVxuICAgIHJldHVybiBhd2FpdCBzdGFydGVkXG4gIH1cblxuICAvKipcbiAgICogRmluaXNoZXMgdGhlIGNhbGxpbmcgc2Vzc2lvbidzIHJvb3QgbGVhc2UuXG4gICAqIEB0ZW1wbGF0ZSBUXG4gICAqIEBwYXJhbSB7e2NhbGxiYWNrOiAoKSA9PiBQcm9taXNlPFQ+LCBzYXZlUG9pbnROYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQsIHN0YXRlOiBDb25uZWN0aW9uU3RhdGUsIHNvY2tldDogaW1wb3J0KFwid3NcIikuV2ViU29ja2V0fX0gYXJncyAtIExlYXNlIGVuZCByZXF1ZXN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn0gLSBTYXZlcG9pbnQgZW5kIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGZpbmlzaFJvb3RMZWFzZSh7Y2FsbGJhY2ssIHNhdmVQb2ludE5hbWUsIHN0YXRlLCBzb2NrZXR9KSB7XG4gICAgY29uc3QgbGVhc2UgPSBzdGF0ZS5sZWFzZVxuICAgIGlmICghbGVhc2UgfHwgbGVhc2Uuc29ja2V0ICE9PSBzb2NrZXQpIHRocm93IG5ldyBFcnJvcihcIlNoYXJlZCB0cmFuc2FjdGlvbiBicm9rZXIgc2Vzc2lvbiBkb2VzIG5vdCBvd24gdGhlIHJvb3QgdHJhbnNhY3Rpb24gbGVhc2VcIilcbiAgICBpZiAoc2F2ZVBvaW50TmFtZSAhPT0gbGVhc2Uuc2F2ZVBvaW50TmFtZSkgdGhyb3cgbmV3IEVycm9yKFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciByb290IHRyYW5zYWN0aW9uIHNhdmVwb2ludCBkb2VzIG5vdCBtYXRjaCBpdHMgbGVhc2VcIilcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VyaWFsaXplTGVhc2UobGVhc2UsIGNhbGxiYWNrKVxuICAgIH0gZmluYWxseSB7XG4gICAgICBzdGF0ZS5sZWFzZSA9IHVuZGVmaW5lZFxuICAgICAgc3RhdGUucm9vdFNlc3Npb25zLmRlbGV0ZShzb2NrZXQpXG4gICAgICBsZWFzZS5yZWxlYXNlKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2VyaWFsaXplcyBvcGVyYXRpb25zIGJlbG9uZ2luZyB0byB0aGUgYWN0aXZlIGxlYXNlIGhvbGRlci5cbiAgICogQHRlbXBsYXRlIFRcbiAgICogQHBhcmFtIHt7b3BlcmF0aW9uczogUHJvbWlzZTx2b2lkPn19IGxlYXNlIC0gQWN0aXZlIGxlYXNlLlxuICAgKiBAcGFyYW0geygpID0+IFByb21pc2U8VD59IGNhbGxiYWNrIC0gT3BlcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUPn0gLSBSZXN1bHQuXG4gICAqL1xuICBhc3luYyBzZXJpYWxpemVMZWFzZShsZWFzZSwgY2FsbGJhY2spIHtcbiAgICBjb25zdCBwcmV2aW91cyA9IGxlYXNlLm9wZXJhdGlvbnNcbiAgICAvKipcbiAgICAgKiBSZWxlYXNlcyB0aGUgaG9sZGVyIG9wZXJhdGlvbiBxdWV1ZS5cbiAgICAgKiBAdHlwZSB7KHZhbHVlPzogdm9pZCkgPT4gdm9pZH1cbiAgICAgKi9cbiAgICBsZXQgcmVsZWFzZSA9ICgpID0+IHt9XG4gICAgY29uc3QgY3VycmVudCA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7IHJlbGVhc2UgPSByZXNvbHZlIH0pXG4gICAgbGVhc2Uub3BlcmF0aW9ucyA9IHByZXZpb3VzLnRoZW4oKCkgPT4gY3VycmVudClcbiAgICBhd2FpdCBwcmV2aW91c1xuICAgIHRyeSB7IHJldHVybiBhd2FpdCBjYWxsYmFjaygpIH0gZmluYWxseSB7IHJlbGVhc2UoKSB9XG4gIH1cblxuICAvKipcbiAgICogUm9sbHMgYmFjayBsZWFzZXMgYWJhbmRvbmVkIGJ5IGEgZGlzY29ubmVjdGVkIHNlc3Npb24uXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwid3NcIikuV2ViU29ja2V0fSBzb2NrZXQgLSBEaXNjb25uZWN0ZWQgc2Vzc2lvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgYWxsIG93bmVkIGxlYXNlcyByZWxlYXNlLlxuICAgKi9cbiAgYXN5bmMgcmVsZWFzZURpc2Nvbm5lY3RlZExlYXNlcyhzb2NrZXQpIHtcbiAgICAvKiogQHR5cGUge0FycmF5PEVycm9yPn0gKi9cbiAgICBjb25zdCBlcnJvcnMgPSBbXVxuICAgIGZvciAoY29uc3QgW2Nvbm5lY3Rpb24sIHN0YXRlXSBvZiB0aGlzLmNvbm5lY3Rpb25TdGF0ZXMpIHtcbiAgICAgIGNvbnN0IGxlYXNlID0gc3RhdGUubGVhc2VcbiAgICAgIGlmICghbGVhc2UgfHwgbGVhc2Uuc29ja2V0ICE9PSBzb2NrZXQpIGNvbnRpbnVlXG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLnNlcmlhbGl6ZUxlYXNlKGxlYXNlLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5yb2xsYmFja1Jvb3RTYXZlUG9pbnQoY29ubmVjdGlvbiwgbGVhc2Uuc2F2ZVBvaW50TmFtZSlcbiAgICAgICAgfSlcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSlcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHN0YXRlLmxlYXNlID0gdW5kZWZpbmVkXG4gICAgICAgIHN0YXRlLnJvb3RTZXNzaW9ucy5kZWxldGUoc29ja2V0KVxuICAgICAgICBsZWFzZS5yZWxlYXNlKClcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgQWdncmVnYXRlRXJyb3IoZXJyb3JzLCBgU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBsZWFzZSBjbGVhbnVwIGZhaWxlZDogJHtlcnJvcnMubWFwKChlcnJvcikgPT4gZXJyb3IubWVzc2FnZSkuam9pbihcIjsgXCIpfWApXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrcyBkZXRhY2hlZCBzb2NrZXQgY2xlYW51cCBhbmQgcmVjb3JkcyBpdHMgZmFpbHVyZSBmb3IgY2xvc2UoKS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCJ3c1wiKS5XZWJTb2NrZXR9IHNvY2tldCAtIENsb3NlZCBzZXNzaW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBTZXR0bGVkIHRyYWNrZWQgY2xlYW51cC5cbiAgICovXG4gIHNjaGVkdWxlU2Vzc2lvbkNsZWFudXAoc29ja2V0KSB7XG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLnNlc3Npb25DbGVhbnVwLmdldChzb2NrZXQpXG4gICAgaWYgKGV4aXN0aW5nKSByZXR1cm4gZXhpc3RpbmdcbiAgICBjb25zdCBjbGVhbnVwID0gdGhpcy5yZWxlYXNlRGlzY29ubmVjdGVkTGVhc2VzKHNvY2tldClcbiAgICAgIC5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgdGhpcy5jbGVhbnVwRXJyb3JzLnB1c2goZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpKVxuICAgICAgfSlcbiAgICAgIC5maW5hbGx5KCgpID0+IHRoaXMuc2Vzc2lvbkNsZWFudXAuZGVsZXRlKHNvY2tldCkpXG4gICAgdGhpcy5zZXNzaW9uQ2xlYW51cC5zZXQoc29ja2V0LCBjbGVhbnVwKVxuICAgIHJldHVybiBjbGVhbnVwXG4gIH1cblxuICAvKipcbiAgICogUm9sbHMgYmFjayBhbmQgcmVtb3ZlcyBhIHJvb3Qgc2F2ZXBvaW50IHNvIGl0IGNhbm5vdCByZW1haW4gYmVuZWF0aCB0aGUgbmV4dCBsZWFzZS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGNvbm5lY3Rpb24gLSBQYXJlbnQgcGh5c2ljYWwgY29ubmVjdGlvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHNhdmVQb2ludE5hbWUgLSBSb290IHNhdmVwb2ludCBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciByb2xsYmFjayBhbmQgcmVsZWFzZS5cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrUm9vdFNhdmVQb2ludChjb25uZWN0aW9uLCBzYXZlUG9pbnROYW1lKSB7XG4gICAgY29uc3QgbWV0aG9kcyA9IC8qKiBAdHlwZSB7e3JlbGVhc2VTYXZlUG9pbnQ6IChuYW1lOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sIHJvbGxiYWNrU2F2ZVBvaW50OiAobmFtZTogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+fX0gKi8gKGNvbm5lY3Rpb24pXG4gICAgLyoqIEB0eXBlIHtBcnJheTxFcnJvcj59ICovXG4gICAgY29uc3QgZXJyb3JzID0gW11cbiAgICB0cnkge1xuICAgICAgYXdhaXQgbWV0aG9kcy5yb2xsYmFja1NhdmVQb2ludChzYXZlUG9pbnROYW1lKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBlcnJvcnMucHVzaChlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSkpXG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBtZXRob2RzLnJlbGVhc2VTYXZlUG9pbnQoc2F2ZVBvaW50TmFtZSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXJyb3JzLnB1c2goZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpKVxuICAgIH1cbiAgICBpZiAoZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBBZ2dyZWdhdGVFcnJvcihlcnJvcnMsIGBTaGFyZWQgdHJhbnNhY3Rpb24gYnJva2VyIGNvdWxkIG5vdCBjbGVhbiByb290IHNhdmVwb2ludCAke3NhdmVQb2ludE5hbWV9OiAke2Vycm9ycy5tYXAoKGVycm9yKSA9PiBlcnJvci5tZXNzYWdlKS5qb2luKFwiOyBcIil9YClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2VyaWFsaXplcyBvcmRpbmFyeSBub24taG9sZGVyIHdvcmsgdGhyb3VnaCB0aGUgY29ubmVjdGlvbiBGSUZPLlxuICAgKiBAdGVtcGxhdGUgVFxuICAgKiBAcGFyYW0ge0Nvbm5lY3Rpb25TdGF0ZX0gc3RhdGUgLSBDb25uZWN0aW9uIHN0YXRlLlxuICAgKiBAcGFyYW0geygpID0+IFByb21pc2U8VD59IGNhbGxiYWNrIC0gV29yay5cbiAgICogQHJldHVybnMge1Byb21pc2U8VD59IC0gV29yayByZXN1bHQuXG4gICAqL1xuICBhc3luYyBzZXJpYWxpemUoc3RhdGUsIGNhbGxiYWNrKSB7XG4gICAgY29uc3QgcHJldmlvdXMgPSBzdGF0ZS5xdWV1ZVxuICAgIC8qKlxuICAgICAqIFJlc29sdmVzIHRoZSBjdXJyZW50IHF1ZXVlIGVudHJ5LlxuICAgICAqIEB0eXBlIHsodmFsdWU/OiB2b2lkKSA9PiB2b2lkfVxuICAgICAqL1xuICAgIGxldCByZWxlYXNlID0gKCkgPT4ge31cbiAgICBjb25zdCBjdXJyZW50ID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHsgcmVsZWFzZSA9IHJlc29sdmUgfSlcbiAgICBjb25zdCBxdWV1ZWQgPSBwcmV2aW91cy50aGVuKCgpID0+IGN1cnJlbnQpXG4gICAgc3RhdGUucXVldWUgPSBxdWV1ZWRcbiAgICBhd2FpdCBwcmV2aW91c1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgY2FsbGJhY2soKVxuICAgIH0gZmluYWxseSB7XG4gICAgICByZWxlYXNlKClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3RvcHMgYWRtaXNzaW9uLCByZXZva2VzIGNhcGFiaWxpdHksIHJlamVjdHMgY2xpZW50cywgYW5kIGRyYWlucyBhY3RpdmUgd29yay5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdHJhbnNwb3J0IHNodXRkb3duLlxuICAgKi9cbiAgYXN5bmMgY2xvc2UoKSB7XG4gICAgaWYgKHRoaXMuY2xvc2VQcm9taXNlKSByZXR1cm4gYXdhaXQgdGhpcy5jbG9zZVByb21pc2VcbiAgICB0aGlzLmNsb3NlUHJvbWlzZSA9IHRoaXMuY2xvc2VUcmFuc3BvcnQoKVxuICAgIHJldHVybiBhd2FpdCB0aGlzLmNsb3NlUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIFBlcmZvcm1zIGRldGVybWluaXN0aWMgdHJhbnNwb3J0IHNodXRkb3duIGFuZCByZXBvcnRzIGNsZWFudXAgZmFpbHVyZXMgbGFzdC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgc2h1dGRvd24gb3IgcmVqZWN0cyB3aXRoIGNsZWFudXAgZXJyb3JzLlxuICAgKi9cbiAgYXN5bmMgY2xvc2VUcmFuc3BvcnQoKSB7XG4gICAgdGhpcy5hY2NlcHRpbmcgPSBmYWxzZVxuICAgIHRoaXMuc2VjcmV0ID0gcmFuZG9tQnl0ZXMoMzIpLnRvU3RyaW5nKFwiYmFzZTY0dXJsXCIpXG4gICAgY29uc3QgY2xvc2luZ1Nlc3Npb25zID0gQXJyYXkuZnJvbSh0aGlzLnNlc3Npb25zKVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGNsb3NpbmdTZXNzaW9ucy5tYXAoYXN5bmMgKHNvY2tldCkgPT4gYXdhaXQgdGhpcy5zY2hlZHVsZVNlc3Npb25DbGVhbnVwKHNvY2tldCkpKVxuICAgIGZvciAoY29uc3Qgc29ja2V0IG9mIGNsb3NpbmdTZXNzaW9ucykgc29ja2V0LmNsb3NlKDEwMDEsIFwiU2hhcmVkIHRyYW5zYWN0aW9uIGJyb2tlciBjbG9zZWRcIilcbiAgICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoQXJyYXkuZnJvbSh0aGlzLmNvbm5lY3Rpb25TdGF0ZXMudmFsdWVzKCkpLm1hcCgoc3RhdGUpID0+IHN0YXRlLnF1ZXVlKSlcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gdGhpcy53ZWJzb2NrZXRTZXJ2ZXIuY2xvc2UoKCkgPT4gcmVzb2x2ZSh1bmRlZmluZWQpKSlcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gdGhpcy5odHRwU2VydmVyLmNsb3NlKCgpID0+IHJlc29sdmUodW5kZWZpbmVkKSkpXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoQXJyYXkuZnJvbSh0aGlzLnNlc3Npb25DbGVhbnVwLnZhbHVlcygpKSlcbiAgICBmb3IgKGNvbnN0IFtjb25uZWN0aW9uLCBjb29yZGluYXRvcl0gb2YgdGhpcy5jb25uZWN0aW9uQ29vcmRpbmF0b3JzKSB7XG4gICAgICBjbGVhclNoYXJlZFRyYW5zYWN0aW9uQ29vcmRpbmF0b3IoY29ubmVjdGlvbiwgY29vcmRpbmF0b3IpXG4gICAgfVxuICAgIGlmICh0aGlzLmNsZWFudXBFcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEFnZ3JlZ2F0ZUVycm9yKHRoaXMuY2xlYW51cEVycm9ycywgYFNoYXJlZCB0cmFuc2FjdGlvbiBicm9rZXIgY2xlYW51cCBmYWlsZWQ6ICR7dGhpcy5jbGVhbnVwRXJyb3JzLm1hcCgoZXJyb3IpID0+IGVycm9yLm1lc3NhZ2UpLmpvaW4oXCI7IFwiKX1gKVxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type EncodedBrokerValue = {
|
|
2
|
+
[TAG]: string;
|
|
3
|
+
value?: string | number | boolean | EncodedBrokerValue[] | Record<string, EncodedBrokerValue>;
|
|
4
|
+
};
|
|
5
|
+
/** @typedef {{[TAG]: string, value?: string | number | boolean | EncodedBrokerValue[] | Record<string, EncodedBrokerValue>}} EncodedBrokerValue */
|
|
6
|
+
declare const TAG = "$velociousSharedTransaction";
|
|
7
|
+
/**
|
|
8
|
+
* Encodes values crossing the test-only shared-transaction transport without
|
|
9
|
+
* relying on JSON's lossy Date, bigint, non-finite-number, or undefined rules.
|
|
10
|
+
* @param {ReturnType<typeof JSON.parse> | bigint | Buffer | Date | Error | undefined} value - Runtime value.
|
|
11
|
+
* @returns {EncodedBrokerValue} - Tagged transport value.
|
|
12
|
+
*/
|
|
13
|
+
export declare function encodeBrokerValue(value: ReturnType<typeof JSON.parse> | bigint | Buffer | Date | Error | undefined): EncodedBrokerValue;
|
|
14
|
+
/**
|
|
15
|
+
* Decodes a tagged broker transport value.
|
|
16
|
+
* @param {EncodedBrokerValue} encoded - Tagged transport value.
|
|
17
|
+
* @returns {ReturnType<typeof JSON.parse> | bigint | Buffer | Date | Error | undefined} - Runtime value.
|
|
18
|
+
*/
|
|
19
|
+
export declare function decodeBrokerValue(encoded: EncodedBrokerValue): ReturnType<typeof JSON.parse> | bigint | Buffer | Date | Error | undefined;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=shared-transaction-codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-transaction-codec.d.ts","sourceRoot":"","sources":["../../../src/testing/shared-transaction-codec.js"],"names":[],"mappings":"AAEI,YAA0H,kBAAkB,GAAlI;IAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,kBAAkB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAAC,CAAoB;AAAhJ,mJAAmJ;AAEnJ,QAAA,MAAM,GAAG,gCAAgC,CAAA;AAEzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAH5B,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,SAGrC,GAF1B,kBAAkB,CAwC9B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAH9B,kBAG8B,GAF5B,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,CAwBtF"}
|