velocious 1.0.699 → 1.0.700

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.
Files changed (42) hide show
  1. package/README.md +1 -2
  2. package/build/configuration-types.js +11 -0
  3. package/build/configuration.js +122 -1
  4. package/build/database/advisory-lock-backend-policy.js +204 -0
  5. package/build/database/advisory-lock-file-backend.js +348 -0
  6. package/build/database/advisory-lock-runner.js +239 -16
  7. package/build/environment-handlers/base.js +13 -0
  8. package/build/environment-handlers/node.js +11 -0
  9. package/build/http-server/server-lock.js +21 -115
  10. package/build/src/configuration-types.d.ts +31 -0
  11. package/build/src/configuration-types.d.ts.map +1 -1
  12. package/build/src/configuration-types.js +11 -1
  13. package/build/src/configuration.d.ts +88 -1
  14. package/build/src/configuration.d.ts.map +1 -1
  15. package/build/src/configuration.js +112 -2
  16. package/build/src/database/advisory-lock-backend-policy.d.ts +145 -0
  17. package/build/src/database/advisory-lock-backend-policy.d.ts.map +1 -0
  18. package/build/src/database/advisory-lock-backend-policy.js +184 -0
  19. package/build/src/database/advisory-lock-file-backend.d.ts +194 -0
  20. package/build/src/database/advisory-lock-file-backend.d.ts.map +1 -0
  21. package/build/src/database/advisory-lock-file-backend.js +313 -0
  22. package/build/src/database/advisory-lock-runner.d.ts +116 -15
  23. package/build/src/database/advisory-lock-runner.d.ts.map +1 -1
  24. package/build/src/database/advisory-lock-runner.js +190 -17
  25. package/build/src/environment-handlers/base.d.ts +14 -0
  26. package/build/src/environment-handlers/base.d.ts.map +1 -1
  27. package/build/src/environment-handlers/base.js +13 -1
  28. package/build/src/environment-handlers/node.d.ts +11 -0
  29. package/build/src/environment-handlers/node.d.ts.map +1 -1
  30. package/build/src/environment-handlers/node.js +11 -1
  31. package/build/src/http-server/server-lock.d.ts +13 -37
  32. package/build/src/http-server/server-lock.d.ts.map +1 -1
  33. package/build/src/http-server/server-lock.js +22 -109
  34. package/package.json +1 -1
  35. package/src/configuration-types.js +11 -0
  36. package/src/configuration.js +122 -1
  37. package/src/database/advisory-lock-backend-policy.js +204 -0
  38. package/src/database/advisory-lock-file-backend.js +348 -0
  39. package/src/database/advisory-lock-runner.js +239 -16
  40. package/src/environment-handlers/base.js +13 -0
  41. package/src/environment-handlers/node.js +11 -0
  42. package/src/http-server/server-lock.js +21 -115
@@ -0,0 +1,313 @@
1
+ // @ts-check
2
+ import { createHash } from "node:crypto";
3
+ import fs from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import wait from "awaitery/build/wait.js";
7
+ /**
8
+ * Owner metadata written inside one file-lock directory.
9
+ * @typedef {object} AdvisoryLockFileOwner
10
+ * @property {number} pid - PID of the holding process.
11
+ * @property {string} hostname - Host of the holding process.
12
+ * @property {string} holderId - Unique id of the acquiring backend instance.
13
+ * @property {string} acquiredAt - ISO timestamp of acquisition.
14
+ * @property {string} leaseExpiresAt - ISO timestamp when the current lease expires without renewal.
15
+ * @property {string} [host] - Extra owner field: HTTP host (server lock only).
16
+ * @property {number} [port] - Extra owner field: HTTP port (server lock only).
17
+ */
18
+ /**
19
+ * Directory-based advisory-lock backend for the STC-210 `file` tier
20
+ * (`docs/advisory-lock-backends.md` tier (d)). This generalizes the pattern
21
+ * already used by `src/http-server/server-lock.js` and the Node SQLite
22
+ * driver's filesystem layer into one reusable backend behind the shared
23
+ * advisory-lock seam:
24
+ *
25
+ * - Atomic publication: a lock is claimed by `fs.mkdtemp` + `fs.rename` onto
26
+ * the stable lock path, so a losing candidate never observes or deletes a
27
+ * half-written owner record.
28
+ * - Lease + renewal: each hold carries a `leaseMs` lease renewed on
29
+ * `renewIntervalMs` while held, so a holder that dies without releasing
30
+ * (or whose PID was recycled) is reclaimable once the lease expires.
31
+ * - Staleness: a lock directory is stale when its owner metadata is
32
+ * unreadable, its lease expired, or its owner is a dead local process
33
+ * (`kill(pid, 0)` → `ESRCH`). Cross-host owners are only reclaimable via
34
+ * lease expiry because PID liveness cannot be probed remotely.
35
+ *
36
+ * This tier provides no fencing tokens (design §8: a file lock has no
37
+ * monotonic authority a partitioned holder can be checked against), so
38
+ * acquisitions report `fencingSupported: false` instead of pretending.
39
+ */
40
+ export default class AdvisoryLockFileBackend {
41
+ /**
42
+ * Creates one file-lock backend.
43
+ * @param {object} args - Backend options.
44
+ * @param {string} args.directory - Directory that holds the lock directories.
45
+ * @param {Record<string, string | number>} [args.extraOwnerFields] - Extra fields merged into every owner metadata record (e.g. the HTTP server lock's host/port).
46
+ * @param {number} [args.leaseMs] - Lease duration for one hold; expired leases make a lock stale. Defaults to 30000.
47
+ * @param {number} [args.renewIntervalMs] - Renewal cadence while holding; must stay below `leaseMs`. Defaults to 10000.
48
+ * @param {"hashed" | "plain"} [args.pathStyle] - `hashed` derives `<safeName>-<hash>.lock` names (advisory-lock tier); `plain` uses `<name>.lock` (HTTP server lock). Defaults to `hashed`.
49
+ * @param {number} [args.pollIntervalMs] - Wait between acquisition retries. Defaults to 50.
50
+ */
51
+ constructor({ directory, extraOwnerFields = {}, leaseMs = 30_000, renewIntervalMs = 10_000, pathStyle = "hashed", pollIntervalMs = 50 }) {
52
+ this.directory = directory;
53
+ this.extraOwnerFields = extraOwnerFields;
54
+ this.leaseMs = leaseMs;
55
+ this.renewIntervalMs = renewIntervalMs;
56
+ this.pathStyle = pathStyle;
57
+ this.pollIntervalMs = pollIntervalMs;
58
+ this.holderId = `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
59
+ /** @type {Map<string, {timer: ReturnType<typeof setInterval>}>} */
60
+ this.holdsByName = new Map();
61
+ }
62
+ /**
63
+ * Resolves the stable lock directory path for one lock name.
64
+ * @param {string} name - Lock name.
65
+ * @returns {string} - Filesystem path for the lock directory.
66
+ */
67
+ lockPathFor(name) {
68
+ if (this.pathStyle === "plain")
69
+ return path.join(this.directory, `${name}.lock`);
70
+ const hash = createHash("sha256").update(name).digest("hex").slice(0, 16);
71
+ const safeName = name.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 64);
72
+ return path.join(this.directory, `${safeName}-${hash}.lock`);
73
+ }
74
+ /**
75
+ * Blocks until the named lock is acquired or `timeoutMs` elapses.
76
+ * @param {string} name - Lock name.
77
+ * @param {{timeoutMs?: number | null}} [args] - Timeout args; `null`, `undefined`, or negative waits indefinitely.
78
+ * @returns {Promise<boolean>} - True when acquired, false when the timeout elapsed.
79
+ */
80
+ async acquire(name, { timeoutMs } = {}) {
81
+ const deadline = typeof timeoutMs === "number" && timeoutMs >= 0 ? Date.now() + timeoutMs : null;
82
+ await this.ensureDirectory();
83
+ // Intentionally looping without a fixed iteration cap — either the
84
+ // publication succeeds, the deadline elapses, or an unexpected error is
85
+ // re-thrown.
86
+ while (true) {
87
+ if (await this.tryAcquire(name))
88
+ return true;
89
+ if (deadline !== null) {
90
+ const remaining = deadline - Date.now();
91
+ if (remaining <= 0)
92
+ return false;
93
+ await wait(Math.min(this.pollIntervalMs, remaining));
94
+ }
95
+ else {
96
+ await wait(this.pollIntervalMs);
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Attempts to acquire the named lock without waiting, reclaiming a stale
102
+ * lock directory when one is found.
103
+ * @param {string} name - Lock name.
104
+ * @returns {Promise<boolean>} - True when this backend became the lock owner.
105
+ */
106
+ async tryAcquire(name) {
107
+ if (this.holdsByName.has(name))
108
+ return false;
109
+ await this.ensureDirectory();
110
+ const lockPath = this.lockPathFor(name);
111
+ if (await this.publishLockDirectory(lockPath))
112
+ return this.startHold(name);
113
+ if (await this.isStale(lockPath)) {
114
+ await fs.rm(lockPath, { recursive: true, force: true });
115
+ if (await this.publishLockDirectory(lockPath))
116
+ return this.startHold(name);
117
+ }
118
+ return false;
119
+ }
120
+ /**
121
+ * Releases the lock only when this backend instance owns it, mirroring the
122
+ * "you can only release locks you own" contract of the database tiers.
123
+ * @param {string} name - Lock name.
124
+ * @returns {Promise<boolean>} - True when the held lock was released.
125
+ */
126
+ async release(name) {
127
+ const hold = this.holdsByName.get(name);
128
+ if (!hold)
129
+ return false;
130
+ this.clearHold(name);
131
+ const owner = await this.readOwner(this.lockPathFor(name));
132
+ if (!owner || owner.holderId !== this.holderId)
133
+ return false;
134
+ await fs.rm(this.lockPathFor(name), { recursive: true, force: true });
135
+ return true;
136
+ }
137
+ /**
138
+ * Runs is held.
139
+ * @param {string} name - Lock name.
140
+ * @returns {Promise<boolean>} - Whether the lock is currently held by a live, unexpired owner.
141
+ */
142
+ async isHeld(name) {
143
+ const lockPath = this.lockPathFor(name);
144
+ try {
145
+ await fs.stat(lockPath);
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ return !await this.isStale(lockPath);
151
+ }
152
+ /**
153
+ * Reads the current owner metadata for diagnostics.
154
+ * @param {string} name - Lock name.
155
+ * @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when a lock directory exists.
156
+ */
157
+ async holderInfo(name) {
158
+ return await this.readOwner(this.lockPathFor(name));
159
+ }
160
+ /**
161
+ * Releases every lock this backend instance currently holds (shutdown path).
162
+ * @returns {Promise<void>} - Resolves after best-effort release of all holds.
163
+ */
164
+ async releaseAllHeld() {
165
+ for (const name of [...this.holdsByName.keys()]) {
166
+ await this.release(name);
167
+ }
168
+ }
169
+ /**
170
+ * Ensures the parent lock directory exists.
171
+ * @returns {Promise<void>} - Resolves after the directory exists.
172
+ */
173
+ async ensureDirectory() {
174
+ await fs.mkdir(this.directory, { recursive: true });
175
+ }
176
+ /**
177
+ * Publishes a fully initialized lock directory with one atomic rename so
178
+ * concurrent candidates cannot observe a half-written owner record.
179
+ * @param {string} lockPath - Stable lock directory path.
180
+ * @returns {Promise<boolean>} - Whether this candidate became the lock owner.
181
+ */
182
+ async publishLockDirectory(lockPath) {
183
+ const candidatePath = await fs.mkdtemp(`${lockPath}.pending-`);
184
+ let published = false;
185
+ try {
186
+ await this.writeOwner(candidatePath);
187
+ try {
188
+ await fs.rename(candidatePath, lockPath);
189
+ published = true;
190
+ return true;
191
+ }
192
+ catch (error) {
193
+ const code = /** @type {Error & {code?: string}} */ (error)?.code;
194
+ if (code === "EEXIST" || code === "ENOTEMPTY")
195
+ return false;
196
+ throw error;
197
+ }
198
+ }
199
+ finally {
200
+ if (!published)
201
+ await fs.rm(candidatePath, { recursive: true, force: true });
202
+ }
203
+ }
204
+ /**
205
+ * Starts lease renewal for a freshly acquired hold.
206
+ * @param {string} name - Lock name.
207
+ * @returns {true} - Always true; the hold is now tracked.
208
+ */
209
+ startHold(name) {
210
+ const timer = setInterval(() => {
211
+ void this.renewHold(name);
212
+ }, this.renewIntervalMs);
213
+ if (typeof timer.unref === "function")
214
+ timer.unref();
215
+ this.holdsByName.set(name, { timer });
216
+ return true;
217
+ }
218
+ /**
219
+ * Extends this instance's lease on one held lock; stops renewing when the
220
+ * directory is no longer ours (the lock was reclaimed).
221
+ * @param {string} name - Lock name.
222
+ * @returns {Promise<void>} - Resolves after the renewal attempt.
223
+ */
224
+ async renewHold(name) {
225
+ const hold = this.holdsByName.get(name);
226
+ if (!hold)
227
+ return;
228
+ const owner = await this.readOwner(this.lockPathFor(name));
229
+ if (!owner || owner.holderId !== this.holderId) {
230
+ this.clearHold(name);
231
+ return;
232
+ }
233
+ await this.writeOwner(this.lockPathFor(name));
234
+ }
235
+ /**
236
+ * Clears the renewal timer for one hold.
237
+ * @param {string} name - Lock name.
238
+ * @returns {void}
239
+ */
240
+ clearHold(name) {
241
+ const hold = this.holdsByName.get(name);
242
+ if (!hold)
243
+ return;
244
+ clearInterval(hold.timer);
245
+ this.holdsByName.delete(name);
246
+ }
247
+ /**
248
+ * Writes owner + lease metadata into a lock directory.
249
+ * @param {string} lockDirPath - Lock directory to write metadata into.
250
+ * @returns {Promise<void>} - Resolves after metadata is written.
251
+ */
252
+ async writeOwner(lockDirPath) {
253
+ /** @type {AdvisoryLockFileOwner} */
254
+ const owner = {
255
+ acquiredAt: new Date().toISOString(),
256
+ holderId: this.holderId,
257
+ hostname: os.hostname(),
258
+ leaseExpiresAt: new Date(Date.now() + this.leaseMs).toISOString(),
259
+ pid: process.pid,
260
+ ...this.extraOwnerFields
261
+ };
262
+ await fs.writeFile(path.join(lockDirPath, "owner.json"), JSON.stringify(owner));
263
+ }
264
+ /**
265
+ * Reads owner metadata from a lock directory.
266
+ * @param {string} lockPath - Lock directory path.
267
+ * @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when readable.
268
+ */
269
+ async readOwner(lockPath) {
270
+ /** @type {string} */
271
+ let rawOwner;
272
+ try {
273
+ rawOwner = await fs.readFile(path.join(lockPath, "owner.json"), "utf8");
274
+ }
275
+ catch {
276
+ return null;
277
+ }
278
+ try {
279
+ return /** @type {AdvisoryLockFileOwner} */ (JSON.parse(rawOwner));
280
+ }
281
+ catch {
282
+ return null;
283
+ }
284
+ }
285
+ /**
286
+ * A lock directory is stale when its metadata is unreadable, its lease has
287
+ * expired, or its owner is a dead process on this host. Cross-host owners
288
+ * are only reclaimable via lease expiry — PID probing is unreliable beyond
289
+ * one host, which is exactly why this tier is the opt-in single-host last
290
+ * resort (design §4/§8).
291
+ * @param {string} lockPath - Lock directory path.
292
+ * @returns {Promise<boolean>} - Whether the lock can be reclaimed.
293
+ */
294
+ async isStale(lockPath) {
295
+ const owner = await this.readOwner(lockPath);
296
+ if (!owner || typeof owner.pid !== "number")
297
+ return true;
298
+ if (owner.leaseExpiresAt && new Date(owner.leaseExpiresAt).getTime() <= Date.now())
299
+ return true;
300
+ if (owner.hostname && owner.hostname !== os.hostname())
301
+ return false;
302
+ try {
303
+ // `kill(pid, 0)` is a no-op signal that fails with ESRCH when the
304
+ // process is gone; permission errors still prove the process exists.
305
+ process.kill(owner.pid, 0);
306
+ return false;
307
+ }
308
+ catch (error) {
309
+ return /** @type {Error & {code?: string}} */ (error).code === "ESRCH";
310
+ }
311
+ }
312
+ }
313
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWR2aXNvcnktbG9jay1maWxlLWJhY2tlbmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZGF0YWJhc2UvYWR2aXNvcnktbG9jay1maWxlLWJhY2tlbmQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDdEMsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDakMsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3hCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSx3QkFBd0IsQ0FBQTtBQUV6Qzs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sdUJBQXVCO0lBQzFDOzs7Ozs7Ozs7T0FTRztJQUNILFlBQVksRUFBQyxTQUFTLEVBQUUsZ0JBQWdCLEdBQUcsRUFBRSxFQUFFLE9BQU8sR0FBRyxNQUFNLEVBQUUsZUFBZSxHQUFHLE1BQU0sRUFBRSxTQUFTLEdBQUcsUUFBUSxFQUFFLGNBQWMsR0FBRyxFQUFFLEVBQUM7UUFDbkksSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUE7UUFDMUIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO1FBQ3hDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO1FBQ3RCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFBO1FBQ3RDLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFBO1FBQzFCLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFBO1FBQ3BDLElBQUksQ0FBQyxRQUFRLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUs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QUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQge2NyZWF0ZUhhc2h9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIlxuaW1wb3J0IG9zIGZyb20gXCJub2RlOm9zXCJcbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIlxuaW1wb3J0IHdhaXQgZnJvbSBcImF3YWl0ZXJ5L2J1aWxkL3dhaXQuanNcIlxuXG4vKipcbiAqIE93bmVyIG1ldGFkYXRhIHdyaXR0ZW4gaW5zaWRlIG9uZSBmaWxlLWxvY2sgZGlyZWN0b3J5LlxuICogQHR5cGVkZWYge29iamVjdH0gQWR2aXNvcnlMb2NrRmlsZU93bmVyXG4gKiBAcHJvcGVydHkge251bWJlcn0gcGlkIC0gUElEIG9mIHRoZSBob2xkaW5nIHByb2Nlc3MuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaG9zdG5hbWUgLSBIb3N0IG9mIHRoZSBob2xkaW5nIHByb2Nlc3MuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaG9sZGVySWQgLSBVbmlxdWUgaWQgb2YgdGhlIGFjcXVpcmluZyBiYWNrZW5kIGluc3RhbmNlLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGFjcXVpcmVkQXQgLSBJU08gdGltZXN0YW1wIG9mIGFjcXVpc2l0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGxlYXNlRXhwaXJlc0F0IC0gSVNPIHRpbWVzdGFtcCB3aGVuIHRoZSBjdXJyZW50IGxlYXNlIGV4cGlyZXMgd2l0aG91dCByZW5ld2FsLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtob3N0XSAtIEV4dHJhIG93bmVyIGZpZWxkOiBIVFRQIGhvc3QgKHNlcnZlciBsb2NrIG9ubHkpLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IFtwb3J0XSAtIEV4dHJhIG93bmVyIGZpZWxkOiBIVFRQIHBvcnQgKHNlcnZlciBsb2NrIG9ubHkpLlxuICovXG5cbi8qKlxuICogRGlyZWN0b3J5LWJhc2VkIGFkdmlzb3J5LWxvY2sgYmFja2VuZCBmb3IgdGhlIFNUQy0yMTAgYGZpbGVgIHRpZXJcbiAqIChgZG9jcy9hZHZpc29yeS1sb2NrLWJhY2tlbmRzLm1kYCB0aWVyIChkKSkuIFRoaXMgZ2VuZXJhbGl6ZXMgdGhlIHBhdHRlcm5cbiAqIGFscmVhZHkgdXNlZCBieSBgc3JjL2h0dHAtc2VydmVyL3NlcnZlci1sb2NrLmpzYCBhbmQgdGhlIE5vZGUgU1FMaXRlXG4gKiBkcml2ZXIncyBmaWxlc3lzdGVtIGxheWVyIGludG8gb25lIHJldXNhYmxlIGJhY2tlbmQgYmVoaW5kIHRoZSBzaGFyZWRcbiAqIGFkdmlzb3J5LWxvY2sgc2VhbTpcbiAqXG4gKiAtIEF0b21pYyBwdWJsaWNhdGlvbjogYSBsb2NrIGlzIGNsYWltZWQgYnkgYGZzLm1rZHRlbXBgICsgYGZzLnJlbmFtZWAgb250b1xuICogICB0aGUgc3RhYmxlIGxvY2sgcGF0aCwgc28gYSBsb3NpbmcgY2FuZGlkYXRlIG5ldmVyIG9ic2VydmVzIG9yIGRlbGV0ZXMgYVxuICogICBoYWxmLXdyaXR0ZW4gb3duZXIgcmVjb3JkLlxuICogLSBMZWFzZSArIHJlbmV3YWw6IGVhY2ggaG9sZCBjYXJyaWVzIGEgYGxlYXNlTXNgIGxlYXNlIHJlbmV3ZWQgb25cbiAqICAgYHJlbmV3SW50ZXJ2YWxNc2Agd2hpbGUgaGVsZCwgc28gYSBob2xkZXIgdGhhdCBkaWVzIHdpdGhvdXQgcmVsZWFzaW5nXG4gKiAgIChvciB3aG9zZSBQSUQgd2FzIHJlY3ljbGVkKSBpcyByZWNsYWltYWJsZSBvbmNlIHRoZSBsZWFzZSBleHBpcmVzLlxuICogLSBTdGFsZW5lc3M6IGEgbG9jayBkaXJlY3RvcnkgaXMgc3RhbGUgd2hlbiBpdHMgb3duZXIgbWV0YWRhdGEgaXNcbiAqICAgdW5yZWFkYWJsZSwgaXRzIGxlYXNlIGV4cGlyZWQsIG9yIGl0cyBvd25lciBpcyBhIGRlYWQgbG9jYWwgcHJvY2Vzc1xuICogICAoYGtpbGwocGlkLCAwKWAg4oaSIGBFU1JDSGApLiBDcm9zcy1ob3N0IG93bmVycyBhcmUgb25seSByZWNsYWltYWJsZSB2aWFcbiAqICAgbGVhc2UgZXhwaXJ5IGJlY2F1c2UgUElEIGxpdmVuZXNzIGNhbm5vdCBiZSBwcm9iZWQgcmVtb3RlbHkuXG4gKlxuICogVGhpcyB0aWVyIHByb3ZpZGVzIG5vIGZlbmNpbmcgdG9rZW5zIChkZXNpZ24gwqc4OiBhIGZpbGUgbG9jayBoYXMgbm9cbiAqIG1vbm90b25pYyBhdXRob3JpdHkgYSBwYXJ0aXRpb25lZCBob2xkZXIgY2FuIGJlIGNoZWNrZWQgYWdhaW5zdCksIHNvXG4gKiBhY3F1aXNpdGlvbnMgcmVwb3J0IGBmZW5jaW5nU3VwcG9ydGVkOiBmYWxzZWAgaW5zdGVhZCBvZiBwcmV0ZW5kaW5nLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBZHZpc29yeUxvY2tGaWxlQmFja2VuZCB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIG9uZSBmaWxlLWxvY2sgYmFja2VuZC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBCYWNrZW5kIG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmRpcmVjdG9yeSAtIERpcmVjdG9yeSB0aGF0IGhvbGRzIHRoZSBsb2NrIGRpcmVjdG9yaWVzLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlcj59IFthcmdzLmV4dHJhT3duZXJGaWVsZHNdIC0gRXh0cmEgZmllbGRzIG1lcmdlZCBpbnRvIGV2ZXJ5IG93bmVyIG1ldGFkYXRhIHJlY29yZCAoZS5nLiB0aGUgSFRUUCBzZXJ2ZXIgbG9jaydzIGhvc3QvcG9ydCkuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5sZWFzZU1zXSAtIExlYXNlIGR1cmF0aW9uIGZvciBvbmUgaG9sZDsgZXhwaXJlZCBsZWFzZXMgbWFrZSBhIGxvY2sgc3RhbGUuIERlZmF1bHRzIHRvIDMwMDAwLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MucmVuZXdJbnRlcnZhbE1zXSAtIFJlbmV3YWwgY2FkZW5jZSB3aGlsZSBob2xkaW5nOyBtdXN0IHN0YXkgYmVsb3cgYGxlYXNlTXNgLiBEZWZhdWx0cyB0byAxMDAwMC5cbiAgICogQHBhcmFtIHtcImhhc2hlZFwiIHwgXCJwbGFpblwifSBbYXJncy5wYXRoU3R5bGVdIC0gYGhhc2hlZGAgZGVyaXZlcyBgPHNhZmVOYW1lPi08aGFzaD4ubG9ja2AgbmFtZXMgKGFkdmlzb3J5LWxvY2sgdGllcik7IGBwbGFpbmAgdXNlcyBgPG5hbWU+LmxvY2tgIChIVFRQIHNlcnZlciBsb2NrKS4gRGVmYXVsdHMgdG8gYGhhc2hlZGAuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5wb2xsSW50ZXJ2YWxNc10gLSBXYWl0IGJldHdlZW4gYWNxdWlzaXRpb24gcmV0cmllcy4gRGVmYXVsdHMgdG8gNTAuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7ZGlyZWN0b3J5LCBleHRyYU93bmVyRmllbGRzID0ge30sIGxlYXNlTXMgPSAzMF8wMDAsIHJlbmV3SW50ZXJ2YWxNcyA9IDEwXzAwMCwgcGF0aFN0eWxlID0gXCJoYXNoZWRcIiwgcG9sbEludGVydmFsTXMgPSA1MH0pIHtcbiAgICB0aGlzLmRpcmVjdG9yeSA9IGRpcmVjdG9yeVxuICAgIHRoaXMuZXh0cmFPd25lckZpZWxkcyA9IGV4dHJhT3duZXJGaWVsZHNcbiAgICB0aGlzLmxlYXNlTXMgPSBsZWFzZU1zXG4gICAgdGhpcy5yZW5ld0ludGVydmFsTXMgPSByZW5ld0ludGVydmFsTXNcbiAgICB0aGlzLnBhdGhTdHlsZSA9IHBhdGhTdHlsZVxuICAgIHRoaXMucG9sbEludGVydmFsTXMgPSBwb2xsSW50ZXJ2YWxNc1xuICAgIHRoaXMuaG9sZGVySWQgPSBgJHtwcm9jZXNzLnBpZH0tJHtEYXRlLm5vdygpfS0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDEwKX1gXG4gICAgLyoqIEB0eXBlIHtNYXA8c3RyaW5nLCB7dGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPn0+fSAqL1xuICAgIHRoaXMuaG9sZHNCeU5hbWUgPSBuZXcgTWFwKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgc3RhYmxlIGxvY2sgZGlyZWN0b3J5IHBhdGggZm9yIG9uZSBsb2NrIG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIEZpbGVzeXN0ZW0gcGF0aCBmb3IgdGhlIGxvY2sgZGlyZWN0b3J5LlxuICAgKi9cbiAgbG9ja1BhdGhGb3IobmFtZSkge1xuICAgIGlmICh0aGlzLnBhdGhTdHlsZSA9PT0gXCJwbGFpblwiKSByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCBgJHtuYW1lfS5sb2NrYClcblxuICAgIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShuYW1lKS5kaWdlc3QoXCJoZXhcIikuc2xpY2UoMCwgMTYpXG4gICAgY29uc3Qgc2FmZU5hbWUgPSBuYW1lLnJlcGxhY2UoL1teYS16QS1aMC05Ll8tXS9nLCBcIl9cIikuc2xpY2UoMCwgNjQpXG5cbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCBgJHtzYWZlTmFtZX0tJHtoYXNofS5sb2NrYClcbiAgfVxuXG4gIC8qKlxuICAgKiBCbG9ja3MgdW50aWwgdGhlIG5hbWVkIGxvY2sgaXMgYWNxdWlyZWQgb3IgYHRpbWVvdXRNc2AgZWxhcHNlcy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUuXG4gICAqIEBwYXJhbSB7e3RpbWVvdXRNcz86IG51bWJlciB8IG51bGx9fSBbYXJnc10gLSBUaW1lb3V0IGFyZ3M7IGBudWxsYCwgYHVuZGVmaW5lZGAsIG9yIG5lZ2F0aXZlIHdhaXRzIGluZGVmaW5pdGVseS5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gVHJ1ZSB3aGVuIGFjcXVpcmVkLCBmYWxzZSB3aGVuIHRoZSB0aW1lb3V0IGVsYXBzZWQuXG4gICAqL1xuICBhc3luYyBhY3F1aXJlKG5hbWUsIHt0aW1lb3V0TXN9ID0ge30pIHtcbiAgICBjb25zdCBkZWFkbGluZSA9IHR5cGVvZiB0aW1lb3V0TXMgPT09IFwibnVtYmVyXCIgJiYgdGltZW91dE1zID49IDAgPyBEYXRlLm5vdygpICsgdGltZW91dE1zIDogbnVsbFxuXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVEaXJlY3RvcnkoKVxuXG4gICAgLy8gSW50ZW50aW9uYWxseSBsb29waW5nIHdpdGhvdXQgYSBmaXhlZCBpdGVyYXRpb24gY2FwIOKAlCBlaXRoZXIgdGhlXG4gICAgLy8gcHVibGljYXRpb24gc3VjY2VlZHMsIHRoZSBkZWFkbGluZSBlbGFwc2VzLCBvciBhbiB1bmV4cGVjdGVkIGVycm9yIGlzXG4gICAgLy8gcmUtdGhyb3duLlxuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICBpZiAoYXdhaXQgdGhpcy50cnlBY3F1aXJlKG5hbWUpKSByZXR1cm4gdHJ1ZVxuXG4gICAgICBpZiAoZGVhZGxpbmUgIT09IG51bGwpIHtcbiAgICAgICAgY29uc3QgcmVtYWluaW5nID0gZGVhZGxpbmUgLSBEYXRlLm5vdygpXG5cbiAgICAgICAgaWYgKHJlbWFpbmluZyA8PSAwKSByZXR1cm4gZmFsc2VcblxuICAgICAgICBhd2FpdCB3YWl0KE1hdGgubWluKHRoaXMucG9sbEludGVydmFsTXMsIHJlbWFpbmluZykpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCB3YWl0KHRoaXMucG9sbEludGVydmFsTXMpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF0dGVtcHRzIHRvIGFjcXVpcmUgdGhlIG5hbWVkIGxvY2sgd2l0aG91dCB3YWl0aW5nLCByZWNsYWltaW5nIGEgc3RhbGVcbiAgICogbG9jayBkaXJlY3Rvcnkgd2hlbiBvbmUgaXMgZm91bmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBUcnVlIHdoZW4gdGhpcyBiYWNrZW5kIGJlY2FtZSB0aGUgbG9jayBvd25lci5cbiAgICovXG4gIGFzeW5jIHRyeUFjcXVpcmUobmFtZSkge1xuICAgIGlmICh0aGlzLmhvbGRzQnlOYW1lLmhhcyhuYW1lKSkgcmV0dXJuIGZhbHNlXG5cbiAgICBhd2FpdCB0aGlzLmVuc3VyZURpcmVjdG9yeSgpXG5cbiAgICBjb25zdCBsb2NrUGF0aCA9IHRoaXMubG9ja1BhdGhGb3IobmFtZSlcblxuICAgIGlmIChhd2FpdCB0aGlzLnB1Ymxpc2hMb2NrRGlyZWN0b3J5KGxvY2tQYXRoKSkgcmV0dXJuIHRoaXMuc3RhcnRIb2xkKG5hbWUpXG5cbiAgICBpZiAoYXdhaXQgdGhpcy5pc1N0YWxlKGxvY2tQYXRoKSkge1xuICAgICAgYXdhaXQgZnMucm0obG9ja1BhdGgsIHtyZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlfSlcblxuICAgICAgaWYgKGF3YWl0IHRoaXMucHVibGlzaExvY2tEaXJlY3RvcnkobG9ja1BhdGgpKSByZXR1cm4gdGhpcy5zdGFydEhvbGQobmFtZSlcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlcyB0aGUgbG9jayBvbmx5IHdoZW4gdGhpcyBiYWNrZW5kIGluc3RhbmNlIG93bnMgaXQsIG1pcnJvcmluZyB0aGVcbiAgICogXCJ5b3UgY2FuIG9ubHkgcmVsZWFzZSBsb2NrcyB5b3Ugb3duXCIgY29udHJhY3Qgb2YgdGhlIGRhdGFiYXNlIHRpZXJzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gVHJ1ZSB3aGVuIHRoZSBoZWxkIGxvY2sgd2FzIHJlbGVhc2VkLlxuICAgKi9cbiAgYXN5bmMgcmVsZWFzZShuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVybiBmYWxzZVxuXG4gICAgdGhpcy5jbGVhckhvbGQobmFtZSlcblxuICAgIGNvbnN0IG93bmVyID0gYXdhaXQgdGhpcy5yZWFkT3duZXIodGhpcy5sb2NrUGF0aEZvcihuYW1lKSlcblxuICAgIGlmICghb3duZXIgfHwgb3duZXIuaG9sZGVySWQgIT09IHRoaXMuaG9sZGVySWQpIHJldHVybiBmYWxzZVxuXG4gICAgYXdhaXQgZnMucm0odGhpcy5sb2NrUGF0aEZvcihuYW1lKSwge3JlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWV9KVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGlzIGhlbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBXaGV0aGVyIHRoZSBsb2NrIGlzIGN1cnJlbnRseSBoZWxkIGJ5IGEgbGl2ZSwgdW5leHBpcmVkIG93bmVyLlxuICAgKi9cbiAgYXN5bmMgaXNIZWxkKG5hbWUpIHtcbiAgICBjb25zdCBsb2NrUGF0aCA9IHRoaXMubG9ja1BhdGhGb3IobmFtZSlcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5zdGF0KGxvY2tQYXRoKVxuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuXG4gICAgcmV0dXJuICFhd2FpdCB0aGlzLmlzU3RhbGUobG9ja1BhdGgpXG4gIH1cblxuICAvKipcbiAgICogUmVhZHMgdGhlIGN1cnJlbnQgb3duZXIgbWV0YWRhdGEgZm9yIGRpYWdub3N0aWNzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8QWR2aXNvcnlMb2NrRmlsZU93bmVyIHwgbnVsbD59IC0gUGFyc2VkIG93bmVyIG1ldGFkYXRhLCB3aGVuIGEgbG9jayBkaXJlY3RvcnkgZXhpc3RzLlxuICAgKi9cbiAgYXN5bmMgaG9sZGVySW5mbyhuYW1lKSB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucmVhZE93bmVyKHRoaXMubG9ja1BhdGhGb3IobmFtZSkpXG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgZXZlcnkgbG9jayB0aGlzIGJhY2tlbmQgaW5zdGFuY2UgY3VycmVudGx5IGhvbGRzIChzaHV0ZG93biBwYXRoKS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgYmVzdC1lZmZvcnQgcmVsZWFzZSBvZiBhbGwgaG9sZHMuXG4gICAqL1xuICBhc3luYyByZWxlYXNlQWxsSGVsZCgpIHtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgWy4uLnRoaXMuaG9sZHNCeU5hbWUua2V5cygpXSkge1xuICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlKG5hbWUpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZXMgdGhlIHBhcmVudCBsb2NrIGRpcmVjdG9yeSBleGlzdHMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBkaXJlY3RvcnkgZXhpc3RzLlxuICAgKi9cbiAgYXN5bmMgZW5zdXJlRGlyZWN0b3J5KCkge1xuICAgIGF3YWl0IGZzLm1rZGlyKHRoaXMuZGlyZWN0b3J5LCB7cmVjdXJzaXZlOiB0cnVlfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoZXMgYSBmdWxseSBpbml0aWFsaXplZCBsb2NrIGRpcmVjdG9yeSB3aXRoIG9uZSBhdG9taWMgcmVuYW1lIHNvXG4gICAqIGNvbmN1cnJlbnQgY2FuZGlkYXRlcyBjYW5ub3Qgb2JzZXJ2ZSBhIGhhbGYtd3JpdHRlbiBvd25lciByZWNvcmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsb2NrUGF0aCAtIFN0YWJsZSBsb2NrIGRpcmVjdG9yeSBwYXRoLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBXaGV0aGVyIHRoaXMgY2FuZGlkYXRlIGJlY2FtZSB0aGUgbG9jayBvd25lci5cbiAgICovXG4gIGFzeW5jIHB1Ymxpc2hMb2NrRGlyZWN0b3J5KGxvY2tQYXRoKSB7XG4gICAgY29uc3QgY2FuZGlkYXRlUGF0aCA9IGF3YWl0IGZzLm1rZHRlbXAoYCR7bG9ja1BhdGh9LnBlbmRpbmctYClcbiAgICBsZXQgcHVibGlzaGVkID0gZmFsc2VcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLndyaXRlT3duZXIoY2FuZGlkYXRlUGF0aClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMucmVuYW1lKGNhbmRpZGF0ZVBhdGgsIGxvY2tQYXRoKVxuICAgICAgICBwdWJsaXNoZWQgPSB0cnVlXG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBjb2RlID0gLyoqIEB0eXBlIHtFcnJvciAmIHtjb2RlPzogc3RyaW5nfX0gKi8gKGVycm9yKT8uY29kZVxuXG4gICAgICAgIGlmIChjb2RlID09PSBcIkVFWElTVFwiIHx8IGNvZGUgPT09IFwiRU5PVEVNUFRZXCIpIHJldHVybiBmYWxzZVxuICAgICAgICB0aHJvdyBlcnJvclxuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAoIXB1Ymxpc2hlZCkgYXdhaXQgZnMucm0oY2FuZGlkYXRlUGF0aCwge3JlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWV9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydHMgbGVhc2UgcmVuZXdhbCBmb3IgYSBmcmVzaGx5IGFjcXVpcmVkIGhvbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7dHJ1ZX0gLSBBbHdheXMgdHJ1ZTsgdGhlIGhvbGQgaXMgbm93IHRyYWNrZWQuXG4gICAqL1xuICBzdGFydEhvbGQobmFtZSkge1xuICAgIGNvbnN0IHRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgdm9pZCB0aGlzLnJlbmV3SG9sZChuYW1lKVxuICAgIH0sIHRoaXMucmVuZXdJbnRlcnZhbE1zKVxuXG4gICAgaWYgKHR5cGVvZiB0aW1lci51bnJlZiA9PT0gXCJmdW5jdGlvblwiKSB0aW1lci51bnJlZigpXG5cbiAgICB0aGlzLmhvbGRzQnlOYW1lLnNldChuYW1lLCB7dGltZXJ9KVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRlbmRzIHRoaXMgaW5zdGFuY2UncyBsZWFzZSBvbiBvbmUgaGVsZCBsb2NrOyBzdG9wcyByZW5ld2luZyB3aGVuIHRoZVxuICAgKiBkaXJlY3RvcnkgaXMgbm8gbG9uZ2VyIG91cnMgKHRoZSBsb2NrIHdhcyByZWNsYWltZWQpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdGhlIHJlbmV3YWwgYXR0ZW1wdC5cbiAgICovXG4gIGFzeW5jIHJlbmV3SG9sZChuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVyblxuXG4gICAgY29uc3Qgb3duZXIgPSBhd2FpdCB0aGlzLnJlYWRPd25lcih0aGlzLmxvY2tQYXRoRm9yKG5hbWUpKVxuXG4gICAgaWYgKCFvd25lciB8fCBvd25lci5ob2xkZXJJZCAhPT0gdGhpcy5ob2xkZXJJZCkge1xuICAgICAgdGhpcy5jbGVhckhvbGQobmFtZSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMud3JpdGVPd25lcih0aGlzLmxvY2tQYXRoRm9yKG5hbWUpKVxuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyB0aGUgcmVuZXdhbCB0aW1lciBmb3Igb25lIGhvbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGNsZWFySG9sZChuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVyblxuXG4gICAgY2xlYXJJbnRlcnZhbChob2xkLnRpbWVyKVxuICAgIHRoaXMuaG9sZHNCeU5hbWUuZGVsZXRlKG5hbWUpXG4gIH1cblxuICAvKipcbiAgICogV3JpdGVzIG93bmVyICsgbGVhc2UgbWV0YWRhdGEgaW50byBhIGxvY2sgZGlyZWN0b3J5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbG9ja0RpclBhdGggLSBMb2NrIGRpcmVjdG9yeSB0byB3cml0ZSBtZXRhZGF0YSBpbnRvLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciBtZXRhZGF0YSBpcyB3cml0dGVuLlxuICAgKi9cbiAgYXN5bmMgd3JpdGVPd25lcihsb2NrRGlyUGF0aCkge1xuICAgIC8qKiBAdHlwZSB7QWR2aXNvcnlMb2NrRmlsZU93bmVyfSAqL1xuICAgIGNvbnN0IG93bmVyID0ge1xuICAgICAgYWNxdWlyZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgaG9sZGVySWQ6IHRoaXMuaG9sZGVySWQsXG4gICAgICBob3N0bmFtZTogb3MuaG9zdG5hbWUoKSxcbiAgICAgIGxlYXNlRXhwaXJlc0F0OiBuZXcgRGF0ZShEYXRlLm5vdygpICsgdGhpcy5sZWFzZU1zKS50b0lTT1N0cmluZygpLFxuICAgICAgcGlkOiBwcm9jZXNzLnBpZCxcbiAgICAgIC4uLnRoaXMuZXh0cmFPd25lckZpZWxkc1xuICAgIH1cblxuICAgIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4obG9ja0RpclBhdGgsIFwib3duZXIuanNvblwiKSwgSlNPTi5zdHJpbmdpZnkob3duZXIpKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlYWRzIG93bmVyIG1ldGFkYXRhIGZyb20gYSBsb2NrIGRpcmVjdG9yeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxvY2tQYXRoIC0gTG9jayBkaXJlY3RvcnkgcGF0aC5cbiAgICogQHJldHVybnMge1Byb21pc2U8QWR2aXNvcnlMb2NrRmlsZU93bmVyIHwgbnVsbD59IC0gUGFyc2VkIG93bmVyIG1ldGFkYXRhLCB3aGVuIHJlYWRhYmxlLlxuICAgKi9cbiAgYXN5bmMgcmVhZE93bmVyKGxvY2tQYXRoKSB7XG4gICAgLyoqIEB0eXBlIHtzdHJpbmd9ICovXG4gICAgbGV0IHJhd093bmVyXG5cbiAgICB0cnkge1xuICAgICAgcmF3T3duZXIgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4obG9ja1BhdGgsIFwib3duZXIuanNvblwiKSwgXCJ1dGY4XCIpXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gLyoqIEB0eXBlIHtBZHZpc29yeUxvY2tGaWxlT3duZXJ9ICovIChKU09OLnBhcnNlKHJhd093bmVyKSlcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEEgbG9jayBkaXJlY3RvcnkgaXMgc3RhbGUgd2hlbiBpdHMgbWV0YWRhdGEgaXMgdW5yZWFkYWJsZSwgaXRzIGxlYXNlIGhhc1xuICAgKiBleHBpcmVkLCBvciBpdHMgb3duZXIgaXMgYSBkZWFkIHByb2Nlc3Mgb24gdGhpcyBob3N0LiBDcm9zcy1ob3N0IG93bmVyc1xuICAgKiBhcmUgb25seSByZWNsYWltYWJsZSB2aWEgbGVhc2UgZXhwaXJ5IOKAlCBQSUQgcHJvYmluZyBpcyB1bnJlbGlhYmxlIGJleW9uZFxuICAgKiBvbmUgaG9zdCwgd2hpY2ggaXMgZXhhY3RseSB3aHkgdGhpcyB0aWVyIGlzIHRoZSBvcHQtaW4gc2luZ2xlLWhvc3QgbGFzdFxuICAgKiByZXNvcnQgKGRlc2lnbiDCpzQvwqc4KS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxvY2tQYXRoIC0gTG9jayBkaXJlY3RvcnkgcGF0aC5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gV2hldGhlciB0aGUgbG9jayBjYW4gYmUgcmVjbGFpbWVkLlxuICAgKi9cbiAgYXN5bmMgaXNTdGFsZShsb2NrUGF0aCkge1xuICAgIGNvbnN0IG93bmVyID0gYXdhaXQgdGhpcy5yZWFkT3duZXIobG9ja1BhdGgpXG5cbiAgICBpZiAoIW93bmVyIHx8IHR5cGVvZiBvd25lci5waWQgIT09IFwibnVtYmVyXCIpIHJldHVybiB0cnVlXG5cbiAgICBpZiAob3duZXIubGVhc2VFeHBpcmVzQXQgJiYgbmV3IERhdGUob3duZXIubGVhc2VFeHBpcmVzQXQpLmdldFRpbWUoKSA8PSBEYXRlLm5vdygpKSByZXR1cm4gdHJ1ZVxuXG4gICAgaWYgKG93bmVyLmhvc3RuYW1lICYmIG93bmVyLmhvc3RuYW1lICE9PSBvcy5ob3N0bmFtZSgpKSByZXR1cm4gZmFsc2VcblxuICAgIHRyeSB7XG4gICAgICAvLyBga2lsbChwaWQsIDApYCBpcyBhIG5vLW9wIHNpZ25hbCB0aGF0IGZhaWxzIHdpdGggRVNSQ0ggd2hlbiB0aGVcbiAgICAgIC8vIHByb2Nlc3MgaXMgZ29uZTsgcGVybWlzc2lvbiBlcnJvcnMgc3RpbGwgcHJvdmUgdGhlIHByb2Nlc3MgZXhpc3RzLlxuICAgICAgcHJvY2Vzcy5raWxsKG93bmVyLnBpZCwgMClcblxuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiAvKiogQHR5cGUge0Vycm9yICYge2NvZGU/OiBzdHJpbmd9fSAqLyAoZXJyb3IpLmNvZGUgPT09IFwiRVNSQ0hcIlxuICAgIH1cbiAgfVxufVxuIl19
@@ -1,3 +1,36 @@
1
+ export type AdvisoryLockBackendProvenance = {
2
+ /**
3
+ * - Tier that served the acquisition.
4
+ */
5
+ backend: import("./advisory-lock-backend-policy.js").AdvisoryLockTier;
6
+ /**
7
+ * - Database driver type when the driver tier served it.
8
+ */
9
+ driverType?: string;
10
+ /**
11
+ * - Whether this tier carries fencing tokens (design §8); the file tier reports false rather than pretending.
12
+ */
13
+ fencingSupported: boolean;
14
+ /**
15
+ * - Backend holder id for the file tier.
16
+ */
17
+ holderId?: string;
18
+ /**
19
+ * - Lock name this provenance belongs to.
20
+ */
21
+ lockName?: string;
22
+ };
23
+ /**
24
+ * Provenance of one advisory-lock acquisition (STC-210 design §3): every
25
+ * held lock reports the tier that actually served it, so a fallback is
26
+ * visible to the callback, in logs, and in `getAdvisoryLockBackendStatus()`.
27
+ * @typedef {object} AdvisoryLockBackendProvenance
28
+ * @property {import("./advisory-lock-backend-policy.js").AdvisoryLockTier} backend - Tier that served the acquisition.
29
+ * @property {string} [driverType] - Database driver type when the driver tier served it.
30
+ * @property {boolean} fencingSupported - Whether this tier carries fencing tokens (design §8); the file tier reports false rather than pretending.
31
+ * @property {string} [holderId] - Backend holder id for the file tier.
32
+ * @property {string} [lockName] - Lock name this provenance belongs to.
33
+ */
1
34
  /**
2
35
  * Thrown when an advisory lock could not be acquired before `timeoutMs` elapsed.
3
36
  */
@@ -69,12 +102,13 @@ export default class AdvisoryLockRunner {
69
102
  * cleanup can release the lock even if callback database work is stuck.
70
103
  * @template T
71
104
  * @param {string} name - Lock name.
72
- * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback to invoke while the lock is held.
105
+ * @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
73
106
  * @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Lock and hold timeout options.
74
107
  * @returns {Promise<T>} - Resolves with the callback result.
75
108
  */
76
109
  withAdvisoryLock<T>(name: string, callback: (args?: {
77
- control: import("awaitery/build/timeout.js").TimeoutControl;
110
+ control?: import("awaitery/build/timeout.js").TimeoutControl;
111
+ lockBackend: AdvisoryLockBackendProvenance;
78
112
  }) => Promise<T>, args?: {
79
113
  timeoutMs?: number | null;
80
114
  holdTimeoutMs?: number | null;
@@ -89,16 +123,18 @@ export default class AdvisoryLockRunner {
89
123
  * cancellation.
90
124
  * @template T
91
125
  * @param {string} name - Lock name.
92
- * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback to invoke while the lock is held.
126
+ * @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
93
127
  * @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Hold timeout options.
94
128
  * @returns {Promise<T>} - Resolves with the callback result.
95
129
  */
96
130
  withAdvisoryLockOrFail<T>(name: string, callback: (args?: {
97
- control: import("awaitery/build/timeout.js").TimeoutControl;
131
+ control?: import("awaitery/build/timeout.js").TimeoutControl;
132
+ lockBackend: AdvisoryLockBackendProvenance;
98
133
  }) => Promise<T>, args?: {
99
134
  holdTimeoutMs?: number | null;
100
135
  dedicatedConnection?: boolean;
101
136
  }): Promise<T>;
137
+ /**
102
138
  /**
103
139
  * Runs a callback if the advisory lock can be acquired without waiting;
104
140
  * otherwise returns a `{acquired: false}` defer result instead of throwing.
@@ -114,12 +150,13 @@ export default class AdvisoryLockRunner {
114
150
  * file lock), so a caller never branches on the backend.
115
151
  * @template T
116
152
  * @param {string} name - Lock name.
117
- * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback to invoke while the lock is held.
153
+ * @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
118
154
  * @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Hold timeout options.
119
155
  * @returns {Promise<{acquired: true, result: T} | {acquired: false, reason: "contended", lockName: string}>} - Either the held-callback result or the defer outcome.
120
156
  */
121
157
  withAdvisoryLockOrDefer<T>(name: string, callback: (args?: {
122
- control: import("awaitery/build/timeout.js").TimeoutControl;
158
+ control?: import("awaitery/build/timeout.js").TimeoutControl;
159
+ lockBackend: AdvisoryLockBackendProvenance;
123
160
  }) => Promise<T>, args?: {
124
161
  holdTimeoutMs?: number | null;
125
162
  dedicatedConnection?: boolean;
@@ -132,19 +169,73 @@ export default class AdvisoryLockRunner {
132
169
  lockName: string;
133
170
  }>;
134
171
  /**
135
- * Runs the lock holder callback and releases the lock from its owning connection.
172
+ * Runs the lock holder callback and releases the lock from its owning backend.
136
173
  * @template T
137
- * @param {{callback: (args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>, connection: import("./drivers/base.js").default, holdTimeoutMs?: number | null, name: string}} args - Locked callback args.
174
+ * @param {{callback: (args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>, holdTimeoutMs?: number | null, lockBackend: AdvisoryLockBackendProvenance, name: string, release: () => Promise<unknown>}} args - Locked callback args.
138
175
  * @returns {Promise<T>} - Resolves with the callback result.
139
176
  */
140
- runLockedCallback<T>({ callback, connection, holdTimeoutMs, name }: {
177
+ runLockedCallback<T>({ callback, holdTimeoutMs, lockBackend, name, release }: {
141
178
  callback: (args?: {
142
- control: import("awaitery/build/timeout.js").TimeoutControl;
179
+ control?: import("awaitery/build/timeout.js").TimeoutControl;
180
+ lockBackend: AdvisoryLockBackendProvenance;
143
181
  }) => Promise<T>;
144
- connection: import("./drivers/base.js").default;
145
182
  holdTimeoutMs?: number | null;
183
+ lockBackend: AdvisoryLockBackendProvenance;
146
184
  name: string;
185
+ release: () => Promise<unknown>;
147
186
  }): Promise<T>;
187
+ /**
188
+ * Resolves the backend policy for one lock name and returns the file
189
+ * backend when the name explicitly opts into the file tier
190
+ * (`preferredTier: "file"` plus `advisoryLocks.backends.file.enabled: true`).
191
+ * A name whose declared minimum tier is cross-host is refused loudly
192
+ * (`AdvisoryLockMinTierRefusedError`) before any contact with the file
193
+ * tier. A name that prefers the file tier while the backend is disabled
194
+ * moves to the driver path (a stronger-or-equal tier), never the other way
195
+ * around. Nothing here ever auto-enables the file tier.
196
+ * @param {string} name - Lock name.
197
+ * @returns {Promise<import("./advisory-lock-file-backend.js").default | null>} - Resolves with the file backend serving this name, or null for the driver path.
198
+ */
199
+ fileBackendForName(name: string): Promise<import("./advisory-lock-file-backend.js").default | null>;
200
+ /**
201
+ * Fail-closed check on the driver path (design §9): an undeclared lock name
202
+ * keeps today's behavior (any driver serves it — full backward
203
+ * compatibility), but a name with an explicit policy entry is refused with
204
+ * `AdvisoryLockBackendUnavailableError` when the configured driver cannot
205
+ * satisfy its minimum tier (e.g. `minTier: "driver-native"` on a SQLite
206
+ * driver, which has no native advisory-lock primitive).
207
+ * @param {string} name - Lock name.
208
+ * @param {AdvisoryLockBackendProvenance} lockBackend - Tier the driver path would serve with.
209
+ * @returns {void}
210
+ */
211
+ assertDriverTierEligible(name: string, lockBackend: AdvisoryLockBackendProvenance): void;
212
+ /**
213
+ * Resolves the wait bound for a file-tier acquisition: an explicit caller
214
+ * `timeoutMs` (including an explicit `null` opt-out) wins, otherwise the
215
+ * same framework default that bounds driver acquisitions applies.
216
+ * @param {{timeoutMs?: number | null}} args - Lock options.
217
+ * @returns {number | null} - Wait bound in milliseconds, or `null` for an indefinite wait.
218
+ */
219
+ fileAcquireTimeoutMs(args: {
220
+ timeoutMs?: number | null;
221
+ }): number | null;
222
+ /**
223
+ * Builds the acquisition provenance for a file-tier hold. The file tier
224
+ * cannot carry fencing tokens, so the limitation is reported on every
225
+ * acquisition rather than silently pretended away (design §8).
226
+ * @param {import("./advisory-lock-file-backend.js").default} backend - Backend that served the acquisition.
227
+ * @param {string} name - Lock name.
228
+ * @returns {AdvisoryLockBackendProvenance} - Acquisition provenance.
229
+ */
230
+ fileProvenance(backend: import("./advisory-lock-file-backend.js").default, name: string): AdvisoryLockBackendProvenance;
231
+ /**
232
+ * Builds the acquisition provenance for a driver-served hold. SQLite has no
233
+ * native advisory-lock primitive, so its emulation tier is reported as
234
+ * `process-local` rather than pretending to be database-native.
235
+ * @param {import("./drivers/base.js").default} connection - Connection that served the acquisition.
236
+ * @returns {AdvisoryLockBackendProvenance} - Acquisition provenance.
237
+ */
238
+ driverProvenance(connection: import("./drivers/base.js").default): AdvisoryLockBackendProvenance;
148
239
  /**
149
240
  * Runs lock work on the caller connection unless `dedicatedConnection` is
150
241
  * requested or a positive hold timeout needs its own lock connection.
@@ -172,16 +263,26 @@ export default class AdvisoryLockRunner {
172
263
  *
173
264
  * The callback receives a `TimeoutControl` from awaitery, enabling cooperative
174
265
  * cancellation via `control.check()`, `control.signal`, `control.timedOut`,
175
- * and `control.remaining()`.
266
+ * and `control.remaining()`, plus `lockBackend` provenance for the tier that
267
+ * served the acquisition.
176
268
  * @template T
177
269
  * @param {string} name - Lock name (for the error message).
178
- * @param {(args?: {control: import("awaitery/build/timeout.js").TimeoutControl}) => Promise<T>} callback - Callback holding the lock.
270
+ * @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback holding the lock.
179
271
  * @param {number | null} [holdTimeoutMs] - Max hold time; falsy disables the timeout.
272
+ * @param {AdvisoryLockBackendProvenance} [lockBackend] - Provenance of the acquisition serving this hold.
180
273
  * @returns {Promise<T>} - Resolves with the callback result.
181
274
  */
182
275
  static runWithAdvisoryLockHoldTimeout<T>(name: string, callback: (args?: {
183
- control: import("awaitery/build/timeout.js").TimeoutControl;
184
- }) => Promise<T>, holdTimeoutMs?: number | null): Promise<T>;
276
+ control?: import("awaitery/build/timeout.js").TimeoutControl;
277
+ lockBackend: AdvisoryLockBackendProvenance;
278
+ }) => Promise<T>, holdTimeoutMs?: number | null, lockBackend?: AdvisoryLockBackendProvenance): Promise<T>;
279
+ /**
280
+ * Neutral provenance for direct `runWithAdvisoryLockHoldTimeout` callers that
281
+ * hold a lock acquired outside this runner.
282
+ * @returns {AdvisoryLockBackendProvenance} - Provenance with an unknown tier.
283
+ */
284
+ static unknownBackendProvenance(): AdvisoryLockBackendProvenance;
185
285
  }
186
286
  export { AdvisoryLockBusyError, AdvisoryLockHoldTimeoutError, AdvisoryLockTimeoutError };
287
+ export { AdvisoryLockBackendUnavailableError, AdvisoryLockMinTierRefusedError } from "./advisory-lock-backend-policy.js";
187
288
  //# sourceMappingURL=advisory-lock-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"advisory-lock-runner.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-runner.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,cAAM,wBAAyB,SAAQ,KAAK;IASnC,QAAQ;IARf;;;;OAIG;IACH,YAAY,OAAO,EAHR,MAGQ,EAAE,EAAC,IAAI,EAAC,EAFhB;QAAC,IAAI,EAAE,MAAM,CAAA;KAEG,EAI1B;CACF;AAED;;GAEG;AACH,cAAM,qBAAsB,SAAQ,KAAK;IAShC,QAAQ;IARf;;;;OAIG;IACH,YAAY,OAAO,EAHR,MAGQ,EAAE,EAAC,IAAI,EAAC,EAFhB;QAAC,IAAI,EAAE,MAAM,CAAA;KAEG,EAI1B;CACF;AAED;;GAEG;AACH,cAAM,4BAA6B,SAAQ,KAAK;IASvC,QAAQ;IARf;;;;OAIG;IACH,YAAY,OAAO,EAHR,MAGQ,EAAE,EAAC,IAAI,EAAC,EAFhB;QAAC,IAAI,EAAE,MAAM,CAAA;KAEG,EAI1B;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,kBAAkB;IAM9B,aAAa;IACb,kBAAkB,QAJmE,OAAO,mBAAmB,EAAE,OAAO;IAKxH,kBAAkB;IAPzB;;;OAGG;IACH,YAAY,EAAC,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAC,EAFxD;QAAC,aAAa,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,OAAO,mBAAmB,EAAE,OAAO,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAExF,EAIlE;IAED;;;;;;;;;;;;;;OAcG;IACG,gBAAgB,CANT,CAAC,EAMS,IAAI,EALhB,MAKgB,EAAE,QAAQ,EAJ1B,CAAC,IAAI,CAAC,EAAE;QAAC,OAAO,EAAE,OAAO,2BAA2B,EAAE,cAAc,CAAA;KAAC,KAAK,OAAO,CAAC,CAAC,CAIzD,EAAE,IAAI,AAHxC,CACA,EADQ;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAGnD,GAFnC,OAAO,CAAC,CAAC,CAAC,CAYtB;IAED;;;;;;;;;;;;OAYG;IACG,sBAAsB,CANf,CAAC,EAMe,IAAI,EALtB,MAKsB,EAAE,QAAQ,EAJhC,CAAC,IAAI,CAAC,EAAE;QAAC,OAAO,EAAE,OAAO,2BAA2B,EAAE,cAAc,CAAA;KAAC,KAAK,OAAO,CAAC,CAAC,CAInD,EAAE,IAAI,AAH9C,CACA,EADQ;QAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAGlB,GAFzC,OAAO,CAAC,CAAC,CAAC,CAYtB;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACG,uBAAuB,CANhB,CAAC,EAMgB,IAAI,EALvB,MAKuB,EAAE,QAAQ,EAJjC,CAAC,IAAI,CAAC,EAAE;QAAC,OAAO,EAAE,OAAO,2BAA2B,EAAE,cAAc,CAAA;KAAC,KAAK,OAAO,CAAC,CAAC,CAIlD,EAAE,IAAI,AAH/C,CACA,EADQ;QAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAGjB,GAF1C,OAAO,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAC,GAAG;QAAC,QAAQ,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,CAAC,CAY3G;IAED;;;;;OAKG;IACG,iBAAiB,CAJV,CAAC,EAIU,EAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAC,EAHxD;QAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE;YAAC,OAAO,EAAE,OAAO,2BAA2B,EAAE,cAAc,CAAA;SAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,mBAAmB,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAGrI,GAFtD,OAAO,CAAC,CAAC,CAAC,CAQtB;IAED;;;;;;;OAOG;IACG,kBAAkB,CALX,CAAC,EAKW,IAAI,EAJlB;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAI3C,EAAE,QAAQ,EAH5B,CAAC,UAAU,EAAE,OAAO,mBAAmB,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAGlC,GAF1B,OAAO,CAAC,CAAC,CAAC,CAUtB;IAED;;;;;;OAMG;IACG,uBAAuB,CAJhB,CAAC,EAIgB,QAAQ,EAH3B,CAAC,UAAU,EAAE,OAAO,mBAAmB,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAGnC,GAFzB,OAAO,CAAC,CAAC,CAAC,CAuBtB;IAED;;;;;;;;;;;;;OAaG;IACH,OAAa,8BAA8B,CAN9B,CAAC,EAM8B,IAAI,EALrC,MAKqC,EAAE,QAAQ,EAJ/C,CAAC,IAAI,CAAC,EAAE;QAAC,OAAO,EAAE,OAAO,2BAA2B,EAAE,cAAc,CAAA;KAAC,KAAK,OAAO,CAAC,CAAC,CAIpC,EAAE,aAAa,AAHtE,CACA,EADQ,MAAM,GAAG,IAGqD,GAF5D,OAAO,CAAC,CAAC,CAAC,CAwBtB;CACF;AAED,OAAO,EAAC,qBAAqB,EAAE,4BAA4B,EAAE,wBAAwB,EAAC,CAAA"}
1
+ {"version":3,"file":"advisory-lock-runner.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-runner.js"],"names":[],"mappings":"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"}