@workflow/world-local 5.0.0-beta.23 → 5.0.0-beta.25
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 +9 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -5
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +26 -21
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -5
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +7 -8
- package/dist/storage/events-storage.d.ts.map +1 -1
- package/dist/storage/events-storage.js +178 -20
- package/dist/storage/helpers.d.ts +37 -0
- package/dist/storage/helpers.d.ts.map +1 -1
- package/dist/storage/helpers.js +95 -21
- package/dist/storage/hook-index.d.ts +50 -0
- package/dist/storage/hook-index.d.ts.map +1 -0
- package/dist/storage/hook-index.js +259 -0
- package/dist/storage/hooks-storage.d.ts.map +1 -1
- package/dist/storage/hooks-storage.js +86 -68
- package/dist/storage/runs-storage.d.ts.map +1 -1
- package/dist/storage/runs-storage.js +6 -3
- package/dist/streamer.d.ts.map +1 -1
- package/dist/streamer.js +79 -62
- package/package.json +4 -4
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
* Hash a hook token to produce a filesystem-safe constraint filename.
|
|
3
3
|
*/
|
|
4
4
|
export declare function hashToken(token: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Path of the exclusive-create lock file that commits a hook's disposal.
|
|
7
|
+
* The `hook_disposed` handler writes this lock BEFORE deleting the token
|
|
8
|
+
* claim and hook entity (and before appending the event to the log), so
|
|
9
|
+
* its existence is the earliest durable evidence that the hook can never
|
|
10
|
+
* be live again.
|
|
11
|
+
*/
|
|
12
|
+
export declare function hookDisposeLockPath(basedir: string, hookId: string, tag?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a hook's disposal has been committed (its dispose lock exists).
|
|
15
|
+
* Mirrors event visibility for tagged worlds: an untagged lock is visible
|
|
16
|
+
* to every tag, a tagged lock only to its own tag.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isHookDisposalCommitted(basedir: string, hookId: string, tag?: string): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Path of the exclusive-create claim file that reserves a hook token.
|
|
21
|
+
*/
|
|
22
|
+
export declare function hookTokenClaimPath(basedir: string, token: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Release (delete) a token claim only if it still points at the releasing
|
|
25
|
+
* hook's own `(runId, hookId)`.
|
|
26
|
+
*
|
|
27
|
+
* Both in-flight releasers — the `hook_disposed` handler and the
|
|
28
|
+
* terminal-run `deleteAllHooksForRun` cleanup — read the hook entity and
|
|
29
|
+
* then delete the claim file. Deleting unconditionally is unsafe across
|
|
30
|
+
* processes: a releaser that stalls between those two operations can
|
|
31
|
+
* outlive a force-release of its stale claim (see
|
|
32
|
+
* `isHookTokenClaimReleasable`) and then delete the NEXT claimant's live
|
|
33
|
+
* claim, transiently breaking token uniqueness. Re-reading the claim and
|
|
34
|
+
* matching its identity here shrinks that window from "a stall of any
|
|
35
|
+
* length" to the adjacent read/delete file ops.
|
|
36
|
+
*
|
|
37
|
+
* A claim that is missing, unreadable, or owned by someone else is left
|
|
38
|
+
* alone — if it is genuinely stale debris, the claimant-side force-release
|
|
39
|
+
* path reaps it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function releaseHookTokenClaimIfOwnedBy(basedir: string, token: string, runId: string, hookId: string): Promise<void>;
|
|
5
42
|
/**
|
|
6
43
|
* Compute the path of the recovery-marker sidecar for a specific
|
|
7
44
|
* `(token, runId, hookId)` triple. Identity is encoded in the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/storage/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/storage/helpers.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,CAQR;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,4BAAwC,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,MAIzC,UAAU,MAAM,KAAG,IAAI,GAAG,IAyBnC,CAAC"}
|
package/dist/storage/helpers.js
CHANGED
|
@@ -1,13 +1,84 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { monotonicFactory } from 'ulid';
|
|
4
|
-
import { stripTag, ulidToDate } from '../fs.js';
|
|
5
|
+
import { resolveWithinBase, stripTag, ulidToDate } from '../fs.js';
|
|
5
6
|
/**
|
|
6
7
|
* Hash a hook token to produce a filesystem-safe constraint filename.
|
|
7
8
|
*/
|
|
8
9
|
export function hashToken(token) {
|
|
9
10
|
return createHash('sha256').update(token).digest('hex');
|
|
10
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Path of the exclusive-create lock file that commits a hook's disposal.
|
|
14
|
+
* The `hook_disposed` handler writes this lock BEFORE deleting the token
|
|
15
|
+
* claim and hook entity (and before appending the event to the log), so
|
|
16
|
+
* its existence is the earliest durable evidence that the hook can never
|
|
17
|
+
* be live again.
|
|
18
|
+
*/
|
|
19
|
+
export function hookDisposeLockPath(basedir, hookId, tag) {
|
|
20
|
+
const name = tag ? `${hookId}.disposed.${tag}` : `${hookId}.disposed`;
|
|
21
|
+
return resolveWithinBase(basedir, '.locks', 'hooks', name);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Whether a hook's disposal has been committed (its dispose lock exists).
|
|
25
|
+
* Mirrors event visibility for tagged worlds: an untagged lock is visible
|
|
26
|
+
* to every tag, a tagged lock only to its own tag.
|
|
27
|
+
*/
|
|
28
|
+
export async function isHookDisposalCommitted(basedir, hookId, tag) {
|
|
29
|
+
const candidates = [hookDisposeLockPath(basedir, hookId)];
|
|
30
|
+
if (tag) {
|
|
31
|
+
candidates.push(hookDisposeLockPath(basedir, hookId, tag));
|
|
32
|
+
}
|
|
33
|
+
for (const lockPath of candidates) {
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(lockPath);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// lock not present at this path
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Path of the exclusive-create claim file that reserves a hook token.
|
|
46
|
+
*/
|
|
47
|
+
export function hookTokenClaimPath(basedir, token) {
|
|
48
|
+
return path.join(basedir, 'hooks', 'tokens', `${hashToken(token)}.json`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Release (delete) a token claim only if it still points at the releasing
|
|
52
|
+
* hook's own `(runId, hookId)`.
|
|
53
|
+
*
|
|
54
|
+
* Both in-flight releasers — the `hook_disposed` handler and the
|
|
55
|
+
* terminal-run `deleteAllHooksForRun` cleanup — read the hook entity and
|
|
56
|
+
* then delete the claim file. Deleting unconditionally is unsafe across
|
|
57
|
+
* processes: a releaser that stalls between those two operations can
|
|
58
|
+
* outlive a force-release of its stale claim (see
|
|
59
|
+
* `isHookTokenClaimReleasable`) and then delete the NEXT claimant's live
|
|
60
|
+
* claim, transiently breaking token uniqueness. Re-reading the claim and
|
|
61
|
+
* matching its identity here shrinks that window from "a stall of any
|
|
62
|
+
* length" to the adjacent read/delete file ops.
|
|
63
|
+
*
|
|
64
|
+
* A claim that is missing, unreadable, or owned by someone else is left
|
|
65
|
+
* alone — if it is genuinely stale debris, the claimant-side force-release
|
|
66
|
+
* path reaps it.
|
|
67
|
+
*/
|
|
68
|
+
export async function releaseHookTokenClaimIfOwnedBy(basedir, token, runId, hookId) {
|
|
69
|
+
const claimPath = hookTokenClaimPath(basedir, token);
|
|
70
|
+
let claim;
|
|
71
|
+
try {
|
|
72
|
+
claim = JSON.parse(await fs.readFile(claimPath, 'utf8'));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (claim.runId !== runId || claim.hookId !== hookId) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
await fs.unlink(claimPath).catch(() => { });
|
|
81
|
+
}
|
|
11
82
|
/**
|
|
12
83
|
* Compute the path of the recovery-marker sidecar for a specific
|
|
13
84
|
* `(token, runId, hookId)` triple. Identity is encoded in the
|
|
@@ -41,26 +112,29 @@ export const monotonicUlid = monotonicFactory(() => Math.random());
|
|
|
41
112
|
* @param idPrefix - The prefix to strip from filenames (e.g., 'wrun', 'evnt', 'step')
|
|
42
113
|
* @returns A function that extracts Date from filename, or null if not extractable
|
|
43
114
|
*/
|
|
44
|
-
export const getObjectCreatedAt = (idPrefix) =>
|
|
45
|
-
//
|
|
46
|
-
// e.g., "wrun_ABC.vitest-0.json" → "wrun_ABC.json"
|
|
47
|
-
const cleanName = stripTag(filename.replace(/\.json$/, '')) + '.json';
|
|
115
|
+
export const getObjectCreatedAt = (idPrefix) => {
|
|
116
|
+
// Compiled once per query instead of once per filename.
|
|
48
117
|
const replaceRegex = new RegExp(`^${idPrefix}_`, 'g');
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
const
|
|
118
|
+
return (filename) => {
|
|
119
|
+
// Strip tag suffix before ULID extraction
|
|
120
|
+
// e.g., "wrun_ABC.vitest-0.json" → "wrun_ABC.json"
|
|
121
|
+
const cleanName = stripTag(filename.replace(/\.json$/, '')) + '.json';
|
|
122
|
+
const dashIndex = cleanName.indexOf('-');
|
|
123
|
+
if (dashIndex === -1) {
|
|
124
|
+
// No dash - extract ULID from the filename (e.g., wrun_ULID.json, evnt_ULID.json)
|
|
125
|
+
const ulid = cleanName.replace(/\.json$/, '').replace(replaceRegex, '');
|
|
126
|
+
return ulidToDate(ulid);
|
|
127
|
+
}
|
|
128
|
+
// For composite keys like {runId}-{stepId}, extract from the appropriate part
|
|
129
|
+
if (idPrefix === 'step') {
|
|
130
|
+
// Steps use sequential IDs (step_0, step_1, etc.) - no timestamp in filename.
|
|
131
|
+
// Return null to skip filename-based optimization and defer to JSON-based filtering.
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
// For events: wrun_ULID-evnt_ULID.json - extract from the eventId part
|
|
135
|
+
const id = cleanName.substring(dashIndex + 1).replace(/\.json$/, '');
|
|
136
|
+
const ulid = id.replace(replaceRegex, '');
|
|
53
137
|
return ulidToDate(ulid);
|
|
54
|
-
}
|
|
55
|
-
// For composite keys like {runId}-{stepId}, extract from the appropriate part
|
|
56
|
-
if (idPrefix === 'step') {
|
|
57
|
-
// Steps use sequential IDs (step_0, step_1, etc.) - no timestamp in filename.
|
|
58
|
-
// Return null to skip filename-based optimization and defer to JSON-based filtering.
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
// For events: wrun_ULID-evnt_ULID.json - extract from the eventId part
|
|
62
|
-
const id = cleanName.substring(dashIndex + 1).replace(/\.json$/, '');
|
|
63
|
-
const ulid = id.replace(replaceRegex, '');
|
|
64
|
-
return ulidToDate(ulid);
|
|
138
|
+
};
|
|
65
139
|
};
|
|
66
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yYWdlL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRWhEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxLQUFhO0lBQ3JDLE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDMUQsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUNwQyxPQUFlLEVBQ2YsS0FBYSxFQUNiLEtBQWEsRUFDYixNQUFjO0lBRWQsK0RBQStEO0lBQy9ELDhEQUE4RDtJQUM5RCwyREFBMkQ7SUFDM0QsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQztTQUM3QixNQUFNLENBQUMsR0FBRyxLQUFLLE9BQU8sS0FBSyxPQUFPLE1BQU0sRUFBRSxDQUFDO1NBQzNDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsR0FBRyxHQUFHLGdCQUFnQixDQUFDLENBQUM7QUFDdkUsQ0FBQztBQUVEOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztBQUVuRTs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FDN0IsQ0FBQyxRQUFnQixFQUFFLEVBQUUsQ0FDckIsQ0FBQyxRQUFnQixFQUFlLEVBQUU7SUFDaEMsMENBQTBDO0lBQzFDLG1EQUFtRDtJQUNuRCxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxPQUFPLENBQUM7SUFFdEUsTUFBTSxZQUFZLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxRQUFRLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN0RCxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRXpDLElBQUksU0FBUyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDckIsa0ZBQWtGO1FBQ2xGLE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDeEUsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxJQUFJLFFBQVEsS0FBSyxNQUFNLEVBQUUsQ0FBQztRQUN4Qiw4RUFBOEU7UUFDOUUscUZBQXFGO1FBQ3JGLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELHVFQUF1RTtJQUN2RSxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3JFLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFDLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFCLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgbW9ub3RvbmljRmFjdG9yeSB9IGZyb20gJ3VsaWQnO1xuaW1wb3J0IHsgc3RyaXBUYWcsIHVsaWRUb0RhdGUgfSBmcm9tICcuLi9mcy5qcyc7XG5cbi8qKlxuICogSGFzaCBhIGhvb2sgdG9rZW4gdG8gcHJvZHVjZSBhIGZpbGVzeXN0ZW0tc2FmZSBjb25zdHJhaW50IGZpbGVuYW1lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzaFRva2VuKHRva2VuOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKHRva2VuKS5kaWdlc3QoJ2hleCcpO1xufVxuXG4vKipcbiAqIENvbXB1dGUgdGhlIHBhdGggb2YgdGhlIHJlY292ZXJ5LW1hcmtlciBzaWRlY2FyIGZvciBhIHNwZWNpZmljXG4gKiBgKHRva2VuLCBydW5JZCwgaG9va0lkKWAgdHJpcGxlLiBJZGVudGl0eSBpcyBlbmNvZGVkIGluIHRoZVxuICogZmlsZW5hbWUgaGFzaCBzbyBkaWZmZXJlbnQgdG9rZW4gbGlmZXRpbWVzIChlLmcuIHRoZSBzYW1lIHRva2VuXG4gKiByZXVzZWQgYnkgYSBsYXRlciBydW4gYWZ0ZXIgdGhlIGZpcnN0IHJ1biB3YXMgZGVsZXRlZCkgbmV2ZXJcbiAqIGNvbnRlbmQgb24gYSBzaW5nbGUgc2lkZWNhciDigJQgd2l0aG91dCBwZXItbGlmZXRpbWUgaWRlbnRpdHksIGFcbiAqIHN0YWxlIG1hcmtlciBzdXJ2aXZpbmcgcHJpb3ItcnVuIGNsZWFudXAgY291bGQgXCJsZWFrXCIgaXRzXG4gKiBldmVudElkIGludG8gdGhlIG5ldyBsaWZldGltZSdzIHJlY292ZXJ5IGFuZCBjYXVzZSBkaXZlcmdlbnRcbiAqIHB1YmxpY2F0aW9uLlxuICpcbiAqIFNlZSBgZXZlbnRzLXN0b3JhZ2UudHNgIGZvciB0aGUgZnVsbCByZWNvdmVyeS1tYXJrZXIgcmF0aW9uYWxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaG9va1JlY292ZXJ5TWFya2VyUGF0aChcbiAgYmFzZWRpcjogc3RyaW5nLFxuICB0b2tlbjogc3RyaW5nLFxuICBydW5JZDogc3RyaW5nLFxuICBob29rSWQ6IHN0cmluZ1xuKTogc3RyaW5nIHtcbiAgLy8gRGlzdGluY3QgZnJvbSBgaGFzaFRva2VuKHRva2VuKWAgc28gYSB0b2tlbidzIGNsYWltIGZpbGUgYW5kXG4gIC8vIGl0cyByZWNvdmVyeSBtYXJrZXIgbGl2ZSBhdCBkaWZmZXJlbnQgcGF0aHMgQU5EIGEgZGlmZmVyZW50XG4gIC8vIGxpZmV0aW1lJ3MgcmVjb3ZlcnkgbWFya2VyIG5ldmVyIGNvbGxpZGVzIHdpdGggdGhpcyBvbmUuXG4gIGNvbnN0IGtleSA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpXG4gICAgLnVwZGF0ZShgJHt0b2tlbn1cXHgwMCR7cnVuSWR9XFx4MDAke2hvb2tJZH1gKVxuICAgIC5kaWdlc3QoJ2hleCcpO1xuICByZXR1cm4gcGF0aC5qb2luKGJhc2VkaXIsICdob29rcycsICd0b2tlbnMnLCBgJHtrZXl9LnJlY292ZXJ5Lmpzb25gKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBtb25vdG9uaWMgVUxJRCBmYWN0b3J5IHRoYXQgZW5zdXJlcyBVTElEcyBhcmUgYWx3YXlzIGluY3JlYXNpbmdcbiAqIGV2ZW4gd2hlbiBnZW5lcmF0ZWQgd2l0aGluIHRoZSBzYW1lIG1pbGxpc2Vjb25kLlxuICovXG5leHBvcnQgY29uc3QgbW9ub3RvbmljVWxpZCA9IG1vbm90b25pY0ZhY3RvcnkoKCkgPT4gTWF0aC5yYW5kb20oKSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGZ1bmN0aW9uIHRvIGV4dHJhY3QgY3JlYXRlZEF0IGRhdGUgZnJvbSBhIGZpbGVuYW1lIGJhc2VkIG9uIFVMSUQuXG4gKiBVc2VkIGZvciBlZmZpY2llbnQgcGFnaW5hdGlvbiB3aXRob3V0IHJlYWRpbmcgZmlsZSBjb250ZW50cy5cbiAqXG4gKiBAcGFyYW0gaWRQcmVmaXggLSBUaGUgcHJlZml4IHRvIHN0cmlwIGZyb20gZmlsZW5hbWVzIChlLmcuLCAnd3J1bicsICdldm50JywgJ3N0ZXAnKVxuICogQHJldHVybnMgQSBmdW5jdGlvbiB0aGF0IGV4dHJhY3RzIERhdGUgZnJvbSBmaWxlbmFtZSwgb3IgbnVsbCBpZiBub3QgZXh0cmFjdGFibGVcbiAqL1xuZXhwb3J0IGNvbnN0IGdldE9iamVjdENyZWF0ZWRBdCA9XG4gIChpZFByZWZpeDogc3RyaW5nKSA9PlxuICAoZmlsZW5hbWU6IHN0cmluZyk6IERhdGUgfCBudWxsID0+IHtcbiAgICAvLyBTdHJpcCB0YWcgc3VmZml4IGJlZm9yZSBVTElEIGV4dHJhY3Rpb25cbiAgICAvLyBlLmcuLCBcIndydW5fQUJDLnZpdGVzdC0wLmpzb25cIiDihpIgXCJ3cnVuX0FCQy5qc29uXCJcbiAgICBjb25zdCBjbGVhbk5hbWUgPSBzdHJpcFRhZyhmaWxlbmFtZS5yZXBsYWNlKC9cXC5qc29uJC8sICcnKSkgKyAnLmpzb24nO1xuXG4gICAgY29uc3QgcmVwbGFjZVJlZ2V4ID0gbmV3IFJlZ0V4cChgXiR7aWRQcmVmaXh9X2AsICdnJyk7XG4gICAgY29uc3QgZGFzaEluZGV4ID0gY2xlYW5OYW1lLmluZGV4T2YoJy0nKTtcblxuICAgIGlmIChkYXNoSW5kZXggPT09IC0xKSB7XG4gICAgICAvLyBObyBkYXNoIC0gZXh0cmFjdCBVTElEIGZyb20gdGhlIGZpbGVuYW1lIChlLmcuLCB3cnVuX1VMSUQuanNvbiwgZXZudF9VTElELmpzb24pXG4gICAgICBjb25zdCB1bGlkID0gY2xlYW5OYW1lLnJlcGxhY2UoL1xcLmpzb24kLywgJycpLnJlcGxhY2UocmVwbGFjZVJlZ2V4LCAnJyk7XG4gICAgICByZXR1cm4gdWxpZFRvRGF0ZSh1bGlkKTtcbiAgICB9XG5cbiAgICAvLyBGb3IgY29tcG9zaXRlIGtleXMgbGlrZSB7cnVuSWR9LXtzdGVwSWR9LCBleHRyYWN0IGZyb20gdGhlIGFwcHJvcHJpYXRlIHBhcnRcbiAgICBpZiAoaWRQcmVmaXggPT09ICdzdGVwJykge1xuICAgICAgLy8gU3RlcHMgdXNlIHNlcXVlbnRpYWwgSURzIChzdGVwXzAsIHN0ZXBfMSwgZXRjLikgLSBubyB0aW1lc3RhbXAgaW4gZmlsZW5hbWUuXG4gICAgICAvLyBSZXR1cm4gbnVsbCB0byBza2lwIGZpbGVuYW1lLWJhc2VkIG9wdGltaXphdGlvbiBhbmQgZGVmZXIgdG8gSlNPTi1iYXNlZCBmaWx0ZXJpbmcuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBGb3IgZXZlbnRzOiB3cnVuX1VMSUQtZXZudF9VTElELmpzb24gLSBleHRyYWN0IGZyb20gdGhlIGV2ZW50SWQgcGFydFxuICAgIGNvbnN0IGlkID0gY2xlYW5OYW1lLnN1YnN0cmluZyhkYXNoSW5kZXggKyAxKS5yZXBsYWNlKC9cXC5qc29uJC8sICcnKTtcbiAgICBjb25zdCB1bGlkID0gaWQucmVwbGFjZShyZXBsYWNlUmVnZXgsICcnKTtcbiAgICByZXR1cm4gdWxpZFRvRGF0ZSh1bGlkKTtcbiAgfTtcbiJdfQ==
|
|
140
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yYWdlL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsQyxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRW5FOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxLQUFhO0lBQ3JDLE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDMUQsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FDakMsT0FBZSxFQUNmLE1BQWMsRUFDZCxHQUFZO0lBRVosTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLFdBQVcsQ0FBQztJQUN0RSxPQUFPLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQzdELENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSx1QkFBdUIsQ0FDM0MsT0FBZSxFQUNmLE1BQWMsRUFDZCxHQUFZO0lBRVosTUFBTSxVQUFVLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUMxRCxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ1IsVUFBVSxDQUFDLElBQUks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QyxFQUFFLENBQUM7WUFDckIsa0ZBQWtGO1lBQ2xGLE1BQU0sSUFBSSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDeEUsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUIsQ0FBQztRQUVELDhFQUE4RTtRQUM5RSxJQUFJLFFBQVEsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUN4Qiw4RUFBOEU7WUFDOUUscUZBQXFGO1lBQ3JGLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELHVFQUF1RTtRQUN2RSxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JFLE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUMsQ0FBQztBQUNKLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgZnMgZnJvbSAnbm9kZTpmcy9wcm9taXNlcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgbW9ub3RvbmljRmFjdG9yeSB9IGZyb20gJ3VsaWQnO1xuaW1wb3J0IHsgcmVzb2x2ZVdpdGhpbkJhc2UsIHN0cmlwVGFnLCB1bGlkVG9EYXRlIH0gZnJvbSAnLi4vZnMuanMnO1xuXG4vKipcbiAqIEhhc2ggYSBob29rIHRva2VuIHRvIHByb2R1Y2UgYSBmaWxlc3lzdGVtLXNhZmUgY29uc3RyYWludCBmaWxlbmFtZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc2hUb2tlbih0b2tlbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZSh0b2tlbikuZGlnZXN0KCdoZXgnKTtcbn1cblxuLyoqXG4gKiBQYXRoIG9mIHRoZSBleGNsdXNpdmUtY3JlYXRlIGxvY2sgZmlsZSB0aGF0IGNvbW1pdHMgYSBob29rJ3MgZGlzcG9zYWwuXG4gKiBUaGUgYGhvb2tfZGlzcG9zZWRgIGhhbmRsZXIgd3JpdGVzIHRoaXMgbG9jayBCRUZPUkUgZGVsZXRpbmcgdGhlIHRva2VuXG4gKiBjbGFpbSBhbmQgaG9vayBlbnRpdHkgKGFuZCBiZWZvcmUgYXBwZW5kaW5nIHRoZSBldmVudCB0byB0aGUgbG9nKSwgc29cbiAqIGl0cyBleGlzdGVuY2UgaXMgdGhlIGVhcmxpZXN0IGR1cmFibGUgZXZpZGVuY2UgdGhhdCB0aGUgaG9vayBjYW4gbmV2ZXJcbiAqIGJlIGxpdmUgYWdhaW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBob29rRGlzcG9zZUxvY2tQYXRoKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIGhvb2tJZDogc3RyaW5nLFxuICB0YWc/OiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIGNvbnN0IG5hbWUgPSB0YWcgPyBgJHtob29rSWR9LmRpc3Bvc2VkLiR7dGFnfWAgOiBgJHtob29rSWR9LmRpc3Bvc2VkYDtcbiAgcmV0dXJuIHJlc29sdmVXaXRoaW5CYXNlKGJhc2VkaXIsICcubG9ja3MnLCAnaG9va3MnLCBuYW1lKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGEgaG9vaydzIGRpc3Bvc2FsIGhhcyBiZWVuIGNvbW1pdHRlZCAoaXRzIGRpc3Bvc2UgbG9jayBleGlzdHMpLlxuICogTWlycm9ycyBldmVudCB2aXNpYmlsaXR5IGZvciB0YWdnZWQgd29ybGRzOiBhbiB1bnRhZ2dlZCBsb2NrIGlzIHZpc2libGVcbiAqIHRvIGV2ZXJ5IHRhZywgYSB0YWdnZWQgbG9jayBvbmx5IHRvIGl0cyBvd24gdGFnLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNIb29rRGlzcG9zYWxDb21taXR0ZWQoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgaG9va0lkOiBzdHJpbmcsXG4gIHRhZz86IHN0cmluZ1xuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IGNhbmRpZGF0ZXMgPSBbaG9va0Rpc3Bvc2VMb2NrUGF0aChiYXNlZGlyLCBob29rSWQpXTtcbiAgaWYgKHRhZykge1xuICAgIGNhbmRpZGF0ZXMucHVzaChob29rRGlzcG9zZUxvY2tQYXRoKGJhc2VkaXIsIGhvb2tJZCwgdGFnKSk7XG4gIH1cbiAgZm9yIChjb25zdCBsb2NrUGF0aCBvZiBjYW5kaWRhdGVzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLmFjY2Vzcyhsb2NrUGF0aCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGxvY2sgbm90IHByZXNlbnQgYXQgdGhpcyBwYXRoXG4gICAgfVxuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBQYXRoIG9mIHRoZSBleGNsdXNpdmUtY3JlYXRlIGNsYWltIGZpbGUgdGhhdCByZXNlcnZlcyBhIGhvb2sgdG9rZW4uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBob29rVG9rZW5DbGFpbVBhdGgoYmFzZWRpcjogc3RyaW5nLCB0b2tlbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHBhdGguam9pbihiYXNlZGlyLCAnaG9va3MnLCAndG9rZW5zJywgYCR7aGFzaFRva2VuKHRva2VuKX0uanNvbmApO1xufVxuXG4vKipcbiAqIFJlbGVhc2UgKGRlbGV0ZSkgYSB0b2tlbiBjbGFpbSBvbmx5IGlmIGl0IHN0aWxsIHBvaW50cyBhdCB0aGUgcmVsZWFzaW5nXG4gKiBob29rJ3Mgb3duIGAocnVuSWQsIGhvb2tJZClgLlxuICpcbiAqIEJvdGggaW4tZmxpZ2h0IHJlbGVhc2VycyDigJQgdGhlIGBob29rX2Rpc3Bvc2VkYCBoYW5kbGVyIGFuZCB0aGVcbiAqIHRlcm1pbmFsLXJ1biBgZGVsZXRlQWxsSG9va3NGb3JSdW5gIGNsZWFudXAg4oCUIHJlYWQgdGhlIGhvb2sgZW50aXR5IGFuZFxuICogdGhlbiBkZWxldGUgdGhlIGNsYWltIGZpbGUuIERlbGV0aW5nIHVuY29uZGl0aW9uYWxseSBpcyB1bnNhZmUgYWNyb3NzXG4gKiBwcm9jZXNzZXM6IGEgcmVsZWFzZXIgdGhhdCBzdGFsbHMgYmV0d2VlbiB0aG9zZSB0d28gb3BlcmF0aW9ucyBjYW5cbiAqIG91dGxpdmUgYSBmb3JjZS1yZWxlYXNlIG9mIGl0cyBzdGFsZSBjbGFpbSAoc2VlXG4gKiBgaXNIb29rVG9rZW5DbGFpbVJlbGVhc2FibGVgKSBhbmQgdGhlbiBkZWxldGUgdGhlIE5FWFQgY2xhaW1hbnQncyBsaXZlXG4gKiBjbGFpbSwgdHJhbnNpZW50bHkgYnJlYWtpbmcgdG9rZW4gdW5pcXVlbmVzcy4gUmUtcmVhZGluZyB0aGUgY2xhaW0gYW5kXG4gKiBtYXRjaGluZyBpdHMgaWRlbnRpdHkgaGVyZSBzaHJpbmtzIHRoYXQgd2luZG93IGZyb20gXCJhIHN0YWxsIG9mIGFueVxuICogbGVuZ3RoXCIgdG8gdGhlIGFkamFjZW50IHJlYWQvZGVsZXRlIGZpbGUgb3BzLlxuICpcbiAqIEEgY2xhaW0gdGhhdCBpcyBtaXNzaW5nLCB1bnJlYWRhYmxlLCBvciBvd25lZCBieSBzb21lb25lIGVsc2UgaXMgbGVmdFxuICogYWxvbmUg4oCUIGlmIGl0IGlzIGdlbnVpbmVseSBzdGFsZSBkZWJyaXMsIHRoZSBjbGFpbWFudC1zaWRlIGZvcmNlLXJlbGVhc2VcbiAqIHBhdGggcmVhcHMgaXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWxlYXNlSG9va1Rva2VuQ2xhaW1JZk93bmVkQnkoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgdG9rZW46IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZyxcbiAgaG9va0lkOiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjbGFpbVBhdGggPSBob29rVG9rZW5DbGFpbVBhdGgoYmFzZWRpciwgdG9rZW4pO1xuICBsZXQgY2xhaW06IHsgcnVuSWQ/OiB1bmtub3duOyBob29rSWQ/OiB1bmtub3duIH07XG4gIHRyeSB7XG4gICAgY2xhaW0gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKGNsYWltUGF0aCwgJ3V0ZjgnKSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAoY2xhaW0ucnVuSWQgIT09IHJ1bklkIHx8IGNsYWltLmhvb2tJZCAhPT0gaG9va0lkKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGF3YWl0IGZzLnVubGluayhjbGFpbVBhdGgpLmNhdGNoKCgpID0+IHt9KTtcbn1cblxuLyoqXG4gKiBDb21wdXRlIHRoZSBwYXRoIG9mIHRoZSByZWNvdmVyeS1tYXJrZXIgc2lkZWNhciBmb3IgYSBzcGVjaWZpY1xuICogYCh0b2tlbiwgcnVuSWQsIGhvb2tJZClgIHRyaXBsZS4gSWRlbnRpdHkgaXMgZW5jb2RlZCBpbiB0aGVcbiAqIGZpbGVuYW1lIGhhc2ggc28gZGlmZmVyZW50IHRva2VuIGxpZmV0aW1lcyAoZS5nLiB0aGUgc2FtZSB0b2tlblxuICogcmV1c2VkIGJ5IGEgbGF0ZXIgcnVuIGFmdGVyIHRoZSBmaXJzdCBydW4gd2FzIGRlbGV0ZWQpIG5ldmVyXG4gKiBjb250ZW5kIG9uIGEgc2luZ2xlIHNpZGVjYXIg4oCUIHdpdGhvdXQgcGVyLWxpZmV0aW1lIGlkZW50aXR5LCBhXG4gKiBzdGFsZSBtYXJrZXIgc3Vydml2aW5nIHByaW9yLXJ1biBjbGVhbnVwIGNvdWxkIFwibGVha1wiIGl0c1xuICogZXZlbnRJZCBpbnRvIHRoZSBuZXcgbGlmZXRpbWUncyByZWNvdmVyeSBhbmQgY2F1c2UgZGl2ZXJnZW50XG4gKiBwdWJsaWNhdGlvbi5cbiAqXG4gKiBTZWUgYGV2ZW50cy1zdG9yYWdlLnRzYCBmb3IgdGhlIGZ1bGwgcmVjb3ZlcnktbWFya2VyIHJhdGlvbmFsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhvb2tSZWNvdmVyeU1hcmtlclBhdGgoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgdG9rZW46IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZyxcbiAgaG9va0lkOiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIC8vIERpc3RpbmN0IGZyb20gYGhhc2hUb2tlbih0b2tlbilgIHNvIGEgdG9rZW4ncyBjbGFpbSBmaWxlIGFuZFxuICAvLyBpdHMgcmVjb3ZlcnkgbWFya2VyIGxpdmUgYXQgZGlmZmVyZW50IHBhdGhzIEFORCBhIGRpZmZlcmVudFxuICAvLyBsaWZldGltZSdzIHJlY292ZXJ5IG1hcmtlciBuZXZlciBjb2xsaWRlcyB3aXRoIHRoaXMgb25lLlxuICBjb25zdCBrZXkgPSBjcmVhdGVIYXNoKCdzaGEyNTYnKVxuICAgIC51cGRhdGUoYCR7dG9rZW59XFx4MDAke3J1bklkfVxceDAwJHtob29rSWR9YClcbiAgICAuZGlnZXN0KCdoZXgnKTtcbiAgcmV0dXJuIHBhdGguam9pbihiYXNlZGlyLCAnaG9va3MnLCAndG9rZW5zJywgYCR7a2V5fS5yZWNvdmVyeS5qc29uYCk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgbW9ub3RvbmljIFVMSUQgZmFjdG9yeSB0aGF0IGVuc3VyZXMgVUxJRHMgYXJlIGFsd2F5cyBpbmNyZWFzaW5nXG4gKiBldmVuIHdoZW4gZ2VuZXJhdGVkIHdpdGhpbiB0aGUgc2FtZSBtaWxsaXNlY29uZC5cbiAqL1xuZXhwb3J0IGNvbnN0IG1vbm90b25pY1VsaWQgPSBtb25vdG9uaWNGYWN0b3J5KCgpID0+IE1hdGgucmFuZG9tKCkpO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0byBleHRyYWN0IGNyZWF0ZWRBdCBkYXRlIGZyb20gYSBmaWxlbmFtZSBiYXNlZCBvbiBVTElELlxuICogVXNlZCBmb3IgZWZmaWNpZW50IHBhZ2luYXRpb24gd2l0aG91dCByZWFkaW5nIGZpbGUgY29udGVudHMuXG4gKlxuICogQHBhcmFtIGlkUHJlZml4IC0gVGhlIHByZWZpeCB0byBzdHJpcCBmcm9tIGZpbGVuYW1lcyAoZS5nLiwgJ3dydW4nLCAnZXZudCcsICdzdGVwJylcbiAqIEByZXR1cm5zIEEgZnVuY3Rpb24gdGhhdCBleHRyYWN0cyBEYXRlIGZyb20gZmlsZW5hbWUsIG9yIG51bGwgaWYgbm90IGV4dHJhY3RhYmxlXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRPYmplY3RDcmVhdGVkQXQgPSAoaWRQcmVmaXg6IHN0cmluZykgPT4ge1xuICAvLyBDb21waWxlZCBvbmNlIHBlciBxdWVyeSBpbnN0ZWFkIG9mIG9uY2UgcGVyIGZpbGVuYW1lLlxuICBjb25zdCByZXBsYWNlUmVnZXggPSBuZXcgUmVnRXhwKGBeJHtpZFByZWZpeH1fYCwgJ2cnKTtcblxuICByZXR1cm4gKGZpbGVuYW1lOiBzdHJpbmcpOiBEYXRlIHwgbnVsbCA9PiB7XG4gICAgLy8gU3RyaXAgdGFnIHN1ZmZpeCBiZWZvcmUgVUxJRCBleHRyYWN0aW9uXG4gICAgLy8gZS5nLiwgXCJ3cnVuX0FCQy52aXRlc3QtMC5qc29uXCIg4oaSIFwid3J1bl9BQkMuanNvblwiXG4gICAgY29uc3QgY2xlYW5OYW1lID0gc3RyaXBUYWcoZmlsZW5hbWUucmVwbGFjZSgvXFwuanNvbiQvLCAnJykpICsgJy5qc29uJztcblxuICAgIGNvbnN0IGRhc2hJbmRleCA9IGNsZWFuTmFtZS5pbmRleE9mKCctJyk7XG5cbiAgICBpZiAoZGFzaEluZGV4ID09PSAtMSkge1xuICAgICAgLy8gTm8gZGFzaCAtIGV4dHJhY3QgVUxJRCBmcm9tIHRoZSBmaWxlbmFtZSAoZS5nLiwgd3J1bl9VTElELmpzb24sIGV2bnRfVUxJRC5qc29uKVxuICAgICAgY29uc3QgdWxpZCA9IGNsZWFuTmFtZS5yZXBsYWNlKC9cXC5qc29uJC8sICcnKS5yZXBsYWNlKHJlcGxhY2VSZWdleCwgJycpO1xuICAgICAgcmV0dXJuIHVsaWRUb0RhdGUodWxpZCk7XG4gICAgfVxuXG4gICAgLy8gRm9yIGNvbXBvc2l0ZSBrZXlzIGxpa2Uge3J1bklkfS17c3RlcElkfSwgZXh0cmFjdCBmcm9tIHRoZSBhcHByb3ByaWF0ZSBwYXJ0XG4gICAgaWYgKGlkUHJlZml4ID09PSAnc3RlcCcpIHtcbiAgICAgIC8vIFN0ZXBzIHVzZSBzZXF1ZW50aWFsIElEcyAoc3RlcF8wLCBzdGVwXzEsIGV0Yy4pIC0gbm8gdGltZXN0YW1wIGluIGZpbGVuYW1lLlxuICAgICAgLy8gUmV0dXJuIG51bGwgdG8gc2tpcCBmaWxlbmFtZS1iYXNlZCBvcHRpbWl6YXRpb24gYW5kIGRlZmVyIHRvIEpTT04tYmFzZWQgZmlsdGVyaW5nLlxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gRm9yIGV2ZW50czogd3J1bl9VTElELWV2bnRfVUxJRC5qc29uIC0gZXh0cmFjdCBmcm9tIHRoZSBldmVudElkIHBhcnRcbiAgICBjb25zdCBpZCA9IGNsZWFuTmFtZS5zdWJzdHJpbmcoZGFzaEluZGV4ICsgMSkucmVwbGFjZSgvXFwuanNvbiQvLCAnJyk7XG4gICAgY29uc3QgdWxpZCA9IGlkLnJlcGxhY2UocmVwbGFjZVJlZ2V4LCAnJyk7XG4gICAgcmV0dXJuIHVsaWRUb0RhdGUodWxpZCk7XG4gIH07XG59O1xuIl19
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Event } from '@workflow/world';
|
|
2
|
+
/** Same visibility rule as event files: untagged is visible to all. */
|
|
3
|
+
export declare function isVisibleToTag(fileId: string, tag: string | undefined): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Record a `hook_created` event in the token- and id-indexes. Must be
|
|
6
|
+
* called before the event is published. Idempotent (`writeExclusive`).
|
|
7
|
+
*/
|
|
8
|
+
export declare function writeHookCreatedIndexEntries(basedir: string, token: string, runId: string, hookId: string, eventId: string, tag?: string): Promise<void>;
|
|
9
|
+
export declare function hookByRunMarkerPath(basedir: string, runId: string, hookId: string, tag?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Record a by-run marker for a hook entity. Must be called before the
|
|
12
|
+
* entity write. Idempotent (`writeExclusive`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeHookByRunMarker(basedir: string, runId: string, hookId: string, tag?: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Delete the by-run marker(s) for a hook. A tagged world also removes
|
|
17
|
+
* the untagged variant, since entity reads fall back tagged→untagged.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deleteHookByRunMarker(basedir: string, runId: string, hookId: string, tag?: string): Promise<void>;
|
|
20
|
+
export interface HookByRunMarker {
|
|
21
|
+
/** fileId of the marker (without `.json`), for deletion. */
|
|
22
|
+
fileId: string;
|
|
23
|
+
/** Parsed marker content, or null when the file is unreadable debris. */
|
|
24
|
+
hookId: string | null;
|
|
25
|
+
tag?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function listHookByRunMarkers(basedir: string, runId: string): Promise<HookByRunMarker[]>;
|
|
28
|
+
export declare function deleteHookByRunMarkerFile(basedir: string, fileId: string): Promise<void>;
|
|
29
|
+
/** Forget completed backfills (data-dir reset / tests). */
|
|
30
|
+
export declare function resetHookIndexEnsureCache(): void;
|
|
31
|
+
/**
|
|
32
|
+
* One-time backfill of the indexes for data directories created before
|
|
33
|
+
* they existed — a single full scan, guarded by a completion marker.
|
|
34
|
+
* Concurrent backfills are safe: all writes are idempotent
|
|
35
|
+
* `writeExclusive` calls with byte-identical content.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ensureHookIndexes(basedir: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Find the newest visible `hook_created` event for a token or hookId.
|
|
40
|
+
* Entries are iterated newest-first (eventIds are ULIDs); dangling or
|
|
41
|
+
* non-matching entries are skipped. Liveness is the caller's job.
|
|
42
|
+
*/
|
|
43
|
+
export declare function findNewestIndexedHookCreatedEvent(basedir: string, index: {
|
|
44
|
+
kind: 'token';
|
|
45
|
+
token: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'id';
|
|
48
|
+
hookId: string;
|
|
49
|
+
}, matches: (event: Event) => boolean, tag?: string): Promise<Event | null>;
|
|
50
|
+
//# sourceMappingURL=hook-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-index.d.ts","sourceRoot":"","sources":["../../src/storage/hook-index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAoE7C,uEAAuE;AACvE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,OAAO,CAET;AAaD;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAER;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC,CAyB5B;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAEf;AAKD,2DAA2D;AAC3D,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtE;AA0ED;;;;GAIG;AACH,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACxE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,EAClC,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAkDvB"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { EventSchema, HookSchema } from '@workflow/world';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { assertSafeEntityId, deleteJSON, hasTag, isUntagged, listJSONFiles, readJSON, resolveWithinBase, stripTag, taggedPath, writeExclusive, } from '../fs.js';
|
|
6
|
+
import { hashToken } from './helpers.js';
|
|
7
|
+
/**
|
|
8
|
+
* Durable secondary indexes for hook lookups. Event files are keyed by
|
|
9
|
+
* `{runId}-{eventId}`, so answering "find the live hook_created event
|
|
10
|
+
* for this token/hookId" used to require scanning the entire global
|
|
11
|
+
* event log — O(total history) on every first-time hook creation.
|
|
12
|
+
*
|
|
13
|
+
* Indexes maintained here:
|
|
14
|
+
* - `hooks/token-index/{sha256(token)}/{eventId}[.tag].json` → `{runId}`
|
|
15
|
+
* - `hooks/id-index/{hookId}/{eventId}[.tag].json` → `{runId}`
|
|
16
|
+
* - `hooks/by-run/{runId}-{hookId}[.tag].json` → `{hookId, tag?}`
|
|
17
|
+
* (per live hook entity, for run-termination cleanup)
|
|
18
|
+
*
|
|
19
|
+
* Crash-ordering invariant: entries are written BEFORE the write they
|
|
20
|
+
* index (event publish / entity write), so a crash can only leave a
|
|
21
|
+
* dangling entry pointing at a write that never landed — readers skip
|
|
22
|
+
* those. A committed event/entity invisible to the index cannot occur.
|
|
23
|
+
*
|
|
24
|
+
* Pre-index data directories are handled by a one-time backfill
|
|
25
|
+
* (`ensureHookIndexes`) guarded by a completion marker.
|
|
26
|
+
*/
|
|
27
|
+
const IndexEntrySchema = z.object({
|
|
28
|
+
runId: z.string(),
|
|
29
|
+
});
|
|
30
|
+
const ByRunMarkerSchema = z.object({
|
|
31
|
+
hookId: z.string(),
|
|
32
|
+
tag: z.string().optional(),
|
|
33
|
+
});
|
|
34
|
+
// No `.json` extension so entity listings never pick it up.
|
|
35
|
+
const INDEX_COMPLETE_MARKER = '.hook-index-complete';
|
|
36
|
+
function tokenIndexDir(basedir, token) {
|
|
37
|
+
return resolveWithinBase(basedir, 'hooks', 'token-index', hashToken(token));
|
|
38
|
+
}
|
|
39
|
+
function idIndexDir(basedir, hookId) {
|
|
40
|
+
assertSafeEntityId('hookId', hookId);
|
|
41
|
+
return resolveWithinBase(basedir, 'hooks', 'id-index', hookId);
|
|
42
|
+
}
|
|
43
|
+
function byRunDir(basedir) {
|
|
44
|
+
return resolveWithinBase(basedir, 'hooks', 'by-run');
|
|
45
|
+
}
|
|
46
|
+
function tagOf(fileId) {
|
|
47
|
+
const stripped = stripTag(fileId);
|
|
48
|
+
return stripped === fileId ? undefined : fileId.slice(stripped.length + 1);
|
|
49
|
+
}
|
|
50
|
+
/** Same visibility rule as event files: untagged is visible to all. */
|
|
51
|
+
export function isVisibleToTag(fileId, tag) {
|
|
52
|
+
return tag ? isUntagged(fileId) || hasTag(fileId, tag) : isUntagged(fileId);
|
|
53
|
+
}
|
|
54
|
+
async function readEventLenient(filePath) {
|
|
55
|
+
try {
|
|
56
|
+
return await readJSON(filePath, EventSchema);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error instanceof SyntaxError || error instanceof z.ZodError) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Record a `hook_created` event in the token- and id-indexes. Must be
|
|
67
|
+
* called before the event is published. Idempotent (`writeExclusive`).
|
|
68
|
+
*/
|
|
69
|
+
export async function writeHookCreatedIndexEntries(basedir, token, runId, hookId, eventId, tag) {
|
|
70
|
+
assertSafeEntityId('runId', runId);
|
|
71
|
+
assertSafeEntityId('eventId', eventId);
|
|
72
|
+
if (tag !== undefined)
|
|
73
|
+
assertSafeEntityId('tag', tag);
|
|
74
|
+
const fileName = tag ? `${eventId}.${tag}.json` : `${eventId}.json`;
|
|
75
|
+
const content = JSON.stringify({ runId });
|
|
76
|
+
await Promise.all([
|
|
77
|
+
writeExclusive(path.join(tokenIndexDir(basedir, token), fileName), content),
|
|
78
|
+
writeExclusive(path.join(idIndexDir(basedir, hookId), fileName), content),
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
export function hookByRunMarkerPath(basedir, runId, hookId, tag) {
|
|
82
|
+
return taggedPath(basedir, 'hooks/by-run', `${runId}-${hookId}`, tag);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Record a by-run marker for a hook entity. Must be called before the
|
|
86
|
+
* entity write. Idempotent (`writeExclusive`).
|
|
87
|
+
*/
|
|
88
|
+
export async function writeHookByRunMarker(basedir, runId, hookId, tag) {
|
|
89
|
+
await writeExclusive(hookByRunMarkerPath(basedir, runId, hookId, tag), JSON.stringify(tag ? { hookId, tag } : { hookId }));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Delete the by-run marker(s) for a hook. A tagged world also removes
|
|
93
|
+
* the untagged variant, since entity reads fall back tagged→untagged.
|
|
94
|
+
*/
|
|
95
|
+
export async function deleteHookByRunMarker(basedir, runId, hookId, tag) {
|
|
96
|
+
await deleteJSON(hookByRunMarkerPath(basedir, runId, hookId, tag));
|
|
97
|
+
if (tag) {
|
|
98
|
+
await deleteJSON(hookByRunMarkerPath(basedir, runId, hookId));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export async function listHookByRunMarkers(basedir, runId) {
|
|
102
|
+
assertSafeEntityId('runId', runId);
|
|
103
|
+
const dir = byRunDir(basedir);
|
|
104
|
+
const prefix = `${runId}-`;
|
|
105
|
+
const out = [];
|
|
106
|
+
for (const fileId of await listJSONFiles(dir)) {
|
|
107
|
+
if (!fileId.startsWith(prefix))
|
|
108
|
+
continue;
|
|
109
|
+
let marker = null;
|
|
110
|
+
try {
|
|
111
|
+
marker = await readJSON(path.join(dir, `${fileId}.json`), ByRunMarkerSchema);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (!(error instanceof SyntaxError || error instanceof z.ZodError)) {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
out.push({
|
|
119
|
+
fileId,
|
|
120
|
+
hookId: marker?.hookId ?? null,
|
|
121
|
+
tag: marker?.tag,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
export async function deleteHookByRunMarkerFile(basedir, fileId) {
|
|
127
|
+
await deleteJSON(path.join(byRunDir(basedir), `${fileId}.json`));
|
|
128
|
+
}
|
|
129
|
+
// Per-process ensure cache; only successful backfills are cached.
|
|
130
|
+
const ensuredBasedirs = new Map();
|
|
131
|
+
/** Forget completed backfills (data-dir reset / tests). */
|
|
132
|
+
export function resetHookIndexEnsureCache() {
|
|
133
|
+
ensuredBasedirs.clear();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* One-time backfill of the indexes for data directories created before
|
|
137
|
+
* they existed — a single full scan, guarded by a completion marker.
|
|
138
|
+
* Concurrent backfills are safe: all writes are idempotent
|
|
139
|
+
* `writeExclusive` calls with byte-identical content.
|
|
140
|
+
*/
|
|
141
|
+
export async function ensureHookIndexes(basedir) {
|
|
142
|
+
const key = path.resolve(basedir);
|
|
143
|
+
let pending = ensuredBasedirs.get(key);
|
|
144
|
+
if (!pending) {
|
|
145
|
+
pending = ensureHookIndexesImpl(key).catch((error) => {
|
|
146
|
+
ensuredBasedirs.delete(key);
|
|
147
|
+
throw error;
|
|
148
|
+
});
|
|
149
|
+
ensuredBasedirs.set(key, pending);
|
|
150
|
+
}
|
|
151
|
+
return pending;
|
|
152
|
+
}
|
|
153
|
+
async function forEachConcurrent(items, concurrency, fn) {
|
|
154
|
+
for (let start = 0; start < items.length; start += concurrency) {
|
|
155
|
+
await Promise.all(items.slice(start, start + concurrency).map(fn));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function ensureHookIndexesImpl(basedir) {
|
|
159
|
+
const markerPath = path.join(basedir, 'hooks', INDEX_COMPLETE_MARKER);
|
|
160
|
+
try {
|
|
161
|
+
await fs.access(markerPath);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Marker absent — backfill below.
|
|
166
|
+
}
|
|
167
|
+
const eventsDir = path.join(basedir, 'events');
|
|
168
|
+
await forEachConcurrent(await listJSONFiles(eventsDir), 32, async (fileId) => {
|
|
169
|
+
const event = await readEventLenient(path.join(eventsDir, `${fileId}.json`));
|
|
170
|
+
if (!event || event.eventType !== 'hook_created')
|
|
171
|
+
return;
|
|
172
|
+
if (typeof event.correlationId !== 'string')
|
|
173
|
+
return;
|
|
174
|
+
const token = event.eventData?.token;
|
|
175
|
+
if (typeof token !== 'string')
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
await writeHookCreatedIndexEntries(basedir, token, event.runId, event.correlationId, event.eventId, tagOf(fileId));
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Unsafe ids cannot have been written by this storage layer; skip.
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
const hooksDir = path.join(basedir, 'hooks');
|
|
185
|
+
await forEachConcurrent(await listJSONFiles(hooksDir), 32, async (fileId) => {
|
|
186
|
+
let hook = null;
|
|
187
|
+
try {
|
|
188
|
+
hook = await readJSON(path.join(hooksDir, `${fileId}.json`), HookSchema);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
if (!(error instanceof SyntaxError || error instanceof z.ZodError)) {
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!hook)
|
|
196
|
+
return;
|
|
197
|
+
try {
|
|
198
|
+
await writeHookByRunMarker(basedir, hook.runId, hook.hookId, tagOf(fileId));
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// Unsafe ids cannot have been written by this storage layer; skip.
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
await writeExclusive(markerPath, '');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Find the newest visible `hook_created` event for a token or hookId.
|
|
208
|
+
* Entries are iterated newest-first (eventIds are ULIDs); dangling or
|
|
209
|
+
* non-matching entries are skipped. Liveness is the caller's job.
|
|
210
|
+
*/
|
|
211
|
+
export async function findNewestIndexedHookCreatedEvent(basedir, index, matches, tag) {
|
|
212
|
+
await ensureHookIndexes(basedir);
|
|
213
|
+
let dir;
|
|
214
|
+
try {
|
|
215
|
+
dir =
|
|
216
|
+
index.kind === 'token'
|
|
217
|
+
? tokenIndexDir(basedir, index.token)
|
|
218
|
+
: idIndexDir(basedir, index.hookId);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const entryIds = (await listJSONFiles(dir))
|
|
224
|
+
.filter((fileId) => isVisibleToTag(fileId, tag))
|
|
225
|
+
.sort((a, b) => stripTag(b).localeCompare(stripTag(a)));
|
|
226
|
+
for (const entryId of entryIds) {
|
|
227
|
+
let entry = null;
|
|
228
|
+
try {
|
|
229
|
+
entry = await readJSON(path.join(dir, `${entryId}.json`), IndexEntrySchema);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (!(error instanceof SyntaxError || error instanceof z.ZodError)) {
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!entry)
|
|
237
|
+
continue;
|
|
238
|
+
const eventId = stripTag(entryId);
|
|
239
|
+
let eventPath;
|
|
240
|
+
try {
|
|
241
|
+
eventPath = taggedPath(basedir, 'events', `${entry.runId}-${eventId}`, tagOf(entryId));
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const event = await readEventLenient(eventPath);
|
|
247
|
+
if (!event)
|
|
248
|
+
continue;
|
|
249
|
+
if (event.eventType !== 'hook_created')
|
|
250
|
+
continue;
|
|
251
|
+
if (typeof event.correlationId !== 'string')
|
|
252
|
+
continue;
|
|
253
|
+
if (!matches(event))
|
|
254
|
+
continue;
|
|
255
|
+
return event;
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9vay1pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdG9yYWdlL2hvb2staW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEMsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBRTdCLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDMUQsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUN4QixPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLFVBQVUsRUFDVixNQUFNLEVBQ04sVUFBVSxFQUNWLGFBQWEsRUFDYixRQUFRLEVBQ1IsaUJBQWlCLEVBQ2pCLFFBQVEsRUFDUixVQUFVLEVBQ1YsY0FBYyxHQUNmLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFekM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFFSCxNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDaEMsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7Q0FDbEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2pDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2xCLEdBQUcsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQzNCLENBQUMsQ0FBQztBQUVILDREQUE0RDtBQUM1RCxNQUFNLHFCQUFxQixHQUFHLHNCQUFzQixDQUFDO0FBRXJELFNBQVMsYUFBYSxDQUFDLE9BQWUsRUFBRSxLQUFhO0lBQ25ELE9BQU8saUJBQWlCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDOUUsQ0FB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SyxRQUFRO1lBQUUsU0FBUztRQUN0RCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztZQUFFLFNBQVM7UUFDOUIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMvcHJvbWlzZXMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB0eXBlIHsgRXZlbnQgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgRXZlbnRTY2hlbWEsIEhvb2tTY2hlbWEgfSBmcm9tICdAd29ya2Zsb3cvd29ybGQnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQge1xuICBhc3NlcnRTYWZlRW50aXR5SWQsXG4gIGRlbGV0ZUpTT04sXG4gIGhhc1RhZyxcbiAgaXNVbnRhZ2dlZCxcbiAgbGlzdEpTT05GaWxlcyxcbiAgcmVhZEpTT04sXG4gIHJlc29sdmVXaXRoaW5CYXNlLFxuICBzdHJpcFRhZyxcbiAgdGFnZ2VkUGF0aCxcbiAgd3JpdGVFeGNsdXNpdmUsXG59IGZyb20gJy4uL2ZzLmpzJztcbmltcG9ydCB7IGhhc2hUb2tlbiB9IGZyb20gJy4vaGVscGVycy5qcyc7XG5cbi8qKlxuICogRHVyYWJsZSBzZWNvbmRhcnkgaW5kZXhlcyBmb3IgaG9vayBsb29rdXBzLiBFdmVudCBmaWxlcyBhcmUga2V5ZWQgYnlcbiAqIGB7cnVuSWR9LXtldmVudElkfWAsIHNvIGFuc3dlcmluZyBcImZpbmQgdGhlIGxpdmUgaG9va19jcmVhdGVkIGV2ZW50XG4gKiBmb3IgdGhpcyB0b2tlbi9ob29rSWRcIiB1c2VkIHRvIHJlcXVpcmUgc2Nhbm5pbmcgdGhlIGVudGlyZSBnbG9iYWxcbiAqIGV2ZW50IGxvZyDigJQgTyh0b3RhbCBoaXN0b3J5KSBvbiBldmVyeSBmaXJzdC10aW1lIGhvb2sgY3JlYXRpb24uXG4gKlxuICogSW5kZXhlcyBtYWludGFpbmVkIGhlcmU6XG4gKiAgIC0gYGhvb2tzL3Rva2VuLWluZGV4L3tzaGEyNTYodG9rZW4pfS97ZXZlbnRJZH1bLnRhZ10uanNvbmAg4oaSIGB7cnVuSWR9YFxuICogICAtIGBob29rcy9pZC1pbmRleC97aG9va0lkfS97ZXZlbnRJZH1bLnRhZ10uanNvbmAg4oaSIGB7cnVuSWR9YFxuICogICAtIGBob29rcy9ieS1ydW4ve3J1bklkfS17aG9va0lkfVsudGFnXS5qc29uYCDihpIgYHtob29rSWQsIHRhZz99YFxuICogICAgIChwZXIgbGl2ZSBob29rIGVudGl0eSwgZm9yIHJ1bi10ZXJtaW5hdGlvbiBjbGVhbnVwKVxuICpcbiAqIENyYXNoLW9yZGVyaW5nIGludmFyaWFudDogZW50cmllcyBhcmUgd3JpdHRlbiBCRUZPUkUgdGhlIHdyaXRlIHRoZXlcbiAqIGluZGV4IChldmVudCBwdWJsaXNoIC8gZW50aXR5IHdyaXRlKSwgc28gYSBjcmFzaCBjYW4gb25seSBsZWF2ZSBhXG4gKiBkYW5nbGluZyBlbnRyeSBwb2ludGluZyBhdCBhIHdyaXRlIHRoYXQgbmV2ZXIgbGFuZGVkIOKAlCByZWFkZXJzIHNraXBcbiAqIHRob3NlLiBBIGNvbW1pdHRlZCBldmVudC9lbnRpdHkgaW52aXNpYmxlIHRvIHRoZSBpbmRleCBjYW5ub3Qgb2NjdXIuXG4gKlxuICogUHJlLWluZGV4IGRhdGEgZGlyZWN0b3JpZXMgYXJlIGhhbmRsZWQgYnkgYSBvbmUtdGltZSBiYWNrZmlsbFxuICogKGBlbnN1cmVIb29rSW5kZXhlc2ApIGd1YXJkZWQgYnkgYSBjb21wbGV0aW9uIG1hcmtlci5cbiAqL1xuXG5jb25zdCBJbmRleEVudHJ5U2NoZW1hID0gei5vYmplY3Qoe1xuICBydW5JZDogei5zdHJpbmcoKSxcbn0pO1xuXG5jb25zdCBCeVJ1bk1hcmtlclNjaGVtYSA9IHoub2JqZWN0KHtcbiAgaG9va0lkOiB6LnN0cmluZygpLFxuICB0YWc6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbn0pO1xuXG4vLyBObyBgLmpzb25gIGV4dGVuc2lvbiBzbyBlbnRpdHkgbGlzdGluZ3MgbmV2ZXIgcGljayBpdCB1cC5cbmNvbnN0IElOREVYX0NPTVBMRVRFX01BUktFUiA9ICcuaG9vay1pbmRleC1jb21wbGV0ZSc7XG5cbmZ1bmN0aW9uIHRva2VuSW5kZXhEaXIoYmFzZWRpcjogc3RyaW5nLCB0b2tlbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHJlc29sdmVXaXRoaW5CYXNlKGJhc2VkaXIsICdob29rcycsICd0b2tlbi1pbmRleCcsIGhhc2hUb2tlbih0b2tlbikpO1xufVxuXG5mdW5jdGlvbiBpZEluZGV4RGlyKGJhc2VkaXI6IHN0cmluZywgaG9va0lkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBhc3NlcnRTYWZlRW50aXR5SWQoJ2hvb2tJZCcsIGhvb2tJZCk7XG4gIHJldHVybiByZXNvbHZlV2l0aGluQmFzZShiYXNlZGlyLCAnaG9va3MnLCAnaWQtaW5kZXgnLCBob29rSWQpO1xufVxuXG5mdW5jdGlvbiBieVJ1bkRpcihiYXNlZGlyOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gcmVzb2x2ZVdpdGhpbkJhc2UoYmFzZWRpciwgJ2hvb2tzJywgJ2J5LXJ1bicpO1xufVxuXG5mdW5jdGlvbiB0YWdPZihmaWxlSWQ6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHN0cmlwcGVkID0gc3RyaXBUYWcoZmlsZUlkKTtcbiAgcmV0dXJuIHN0cmlwcGVkID09PSBmaWxlSWQgPyB1bmRlZmluZWQgOiBmaWxlSWQuc2xpY2Uoc3RyaXBwZWQubGVuZ3RoICsgMSk7XG59XG5cbi8qKiBTYW1lIHZpc2liaWxpdHkgcnVsZSBhcyBldmVudCBmaWxlczogdW50YWdnZWQgaXMgdmlzaWJsZSB0byBhbGwuICovXG5leHBvcnQgZnVuY3Rpb24gaXNWaXNpYmxlVG9UYWcoXG4gIGZpbGVJZDogc3RyaW5nLFxuICB0YWc6IHN0cmluZyB8IHVuZGVmaW5lZFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiB0YWcgPyBpc1VudGFnZ2VkKGZpbGVJZCkgfHwgaGFzVGFnKGZpbGVJZCwgdGFnKSA6IGlzVW50YWdnZWQoZmlsZUlkKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZEV2ZW50TGVuaWVudChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxFdmVudCB8IG51bGw+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgcmVhZEpTT04oZmlsZVBhdGgsIEV2ZW50U2NoZW1hKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTeW50YXhFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIHouWm9kRXJyb3IpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG4vKipcbiAqIFJlY29yZCBhIGBob29rX2NyZWF0ZWRgIGV2ZW50IGluIHRoZSB0b2tlbi0gYW5kIGlkLWluZGV4ZXMuIE11c3QgYmVcbiAqIGNhbGxlZCBiZWZvcmUgdGhlIGV2ZW50IGlzIHB1Ymxpc2hlZC4gSWRlbXBvdGVudCAoYHdyaXRlRXhjbHVzaXZlYCkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3cml0ZUhvb2tDcmVhdGVkSW5kZXhFbnRyaWVzKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHRva2VuOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhvb2tJZDogc3RyaW5nLFxuICBldmVudElkOiBzdHJpbmcsXG4gIHRhZz86IHN0cmluZ1xuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGFzc2VydFNhZmVFbnRpdHlJZCgncnVuSWQnLCBydW5JZCk7XG4gIGFzc2VydFNhZmVFbnRpdHlJZCgnZXZlbnRJZCcsIGV2ZW50SWQpO1xuICBpZiAodGFnICE9PSB1bmRlZmluZWQpIGFzc2VydFNhZmVFbnRpdHlJZCgndGFnJywgdGFnKTtcbiAgY29uc3QgZmlsZU5hbWUgPSB0YWcgPyBgJHtldmVudElkfS4ke3RhZ30uanNvbmAgOiBgJHtldmVudElkfS5qc29uYDtcbiAgY29uc3QgY29udGVudCA9IEpTT04uc3RyaW5naWZ5KHsgcnVuSWQgfSk7XG4gIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICB3cml0ZUV4Y2x1c2l2ZShwYXRoLmpvaW4odG9rZW5JbmRleERpcihiYXNlZGlyLCB0b2tlbiksIGZpbGVOYW1lKSwgY29udGVudCksXG4gICAgd3JpdGVFeGNsdXNpdmUocGF0aC5qb2luKGlkSW5kZXhEaXIoYmFzZWRpciwgaG9va0lkKSwgZmlsZU5hbWUpLCBjb250ZW50KSxcbiAgXSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBob29rQnlSdW5NYXJrZXJQYXRoKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhvb2tJZDogc3RyaW5nLFxuICB0YWc/OiBzdHJpbmdcbik6IHN0cmluZyB7XG4gIHJldHVybiB0YWdnZWRQYXRoKGJhc2VkaXIsICdob29rcy9ieS1ydW4nLCBgJHtydW5JZH0tJHtob29rSWR9YCwgdGFnKTtcbn1cblxuLyoqXG4gKiBSZWNvcmQgYSBieS1ydW4gbWFya2VyIGZvciBhIGhvb2sgZW50aXR5LiBNdXN0IGJlIGNhbGxlZCBiZWZvcmUgdGhlXG4gKiBlbnRpdHkgd3JpdGUuIElkZW1wb3RlbnQgKGB3cml0ZUV4Y2x1c2l2ZWApLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVIb29rQnlSdW5NYXJrZXIoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZyxcbiAgaG9va0lkOiBzdHJpbmcsXG4gIHRhZz86IHN0cmluZ1xuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHdyaXRlRXhjbHVzaXZlKFxuICAgIGhvb2tCeVJ1bk1hcmtlclBhdGgoYmFzZWRpciwgcnVuSWQsIGhvb2tJZCwgdGFnKSxcbiAgICBKU09OLnN0cmluZ2lmeSh0YWcgPyB7IGhvb2tJZCwgdGFnIH0gOiB7IGhvb2tJZCB9KVxuICApO1xufVxuXG4vKipcbiAqIERlbGV0ZSB0aGUgYnktcnVuIG1hcmtlcihzKSBmb3IgYSBob29rLiBBIHRhZ2dlZCB3b3JsZCBhbHNvIHJlbW92ZXNcbiAqIHRoZSB1bnRhZ2dlZCB2YXJpYW50LCBzaW5jZSBlbnRpdHkgcmVhZHMgZmFsbCBiYWNrIHRhZ2dlZOKGknVudGFnZ2VkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVsZXRlSG9va0J5UnVuTWFya2VyKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIHJ1bklkOiBzdHJpbmcsXG4gIGhvb2tJZDogc3RyaW5nLFxuICB0YWc/OiBzdHJpbmdcbik6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBkZWxldGVKU09OKGhvb2tCeVJ1bk1hcmtlclBhdGgoYmFzZWRpciwgcnVuSWQsIGhvb2tJZCwgdGFnKSk7XG4gIGlmICh0YWcpIHtcbiAgICBhd2FpdCBkZWxldGVKU09OKGhvb2tCeVJ1bk1hcmtlclBhdGgoYmFzZWRpciwgcnVuSWQsIGhvb2tJZCkpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSG9va0J5UnVuTWFya2VyIHtcbiAgLyoqIGZpbGVJZCBvZiB0aGUgbWFya2VyICh3aXRob3V0IGAuanNvbmApLCBmb3IgZGVsZXRpb24uICovXG4gIGZpbGVJZDogc3RyaW5nO1xuICAvKiogUGFyc2VkIG1hcmtlciBjb250ZW50LCBvciBudWxsIHdoZW4gdGhlIGZpbGUgaXMgdW5yZWFkYWJsZSBkZWJyaXMuICovXG4gIGhvb2tJZDogc3RyaW5nIHwgbnVsbDtcbiAgdGFnPzogc3RyaW5nO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGlzdEhvb2tCeVJ1bk1hcmtlcnMoXG4gIGJhc2VkaXI6IHN0cmluZyxcbiAgcnVuSWQ6IHN0cmluZ1xuKTogUHJvbWlzZTxIb29rQnlSdW5NYXJrZXJbXT4ge1xuICBhc3NlcnRTYWZlRW50aXR5SWQoJ3J1bklkJywgcnVuSWQpO1xuICBjb25zdCBkaXIgPSBieVJ1bkRpcihiYXNlZGlyKTtcbiAgY29uc3QgcHJlZml4ID0gYCR7cnVuSWR9LWA7XG4gIGNvbnN0IG91dDogSG9va0J5UnVuTWFya2VyW10gPSBbXTtcbiAgZm9yIChjb25zdCBmaWxlSWQgb2YgYXdhaXQgbGlzdEpTT05GaWxlcyhkaXIpKSB7XG4gICAgaWYgKCFmaWxlSWQuc3RhcnRzV2l0aChwcmVmaXgpKSBjb250aW51ZTtcbiAgICBsZXQgbWFya2VyOiB6LmluZmVyPHR5cGVvZiBCeVJ1bk1hcmtlclNjaGVtYT4gfCBudWxsID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgbWFya2VyID0gYXdhaXQgcmVhZEpTT04oXG4gICAgICAgIHBhdGguam9pbihkaXIsIGAke2ZpbGVJZH0uanNvbmApLFxuICAgICAgICBCeVJ1bk1hcmtlclNjaGVtYVxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKCEoZXJyb3IgaW5zdGFuY2VvZiBTeW50YXhFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIHouWm9kRXJyb3IpKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgIH1cbiAgICBvdXQucHVzaCh7XG4gICAgICBmaWxlSWQsXG4gICAgICBob29rSWQ6IG1hcmtlcj8uaG9va0lkID8/IG51bGwsXG4gICAgICB0YWc6IG1hcmtlcj8udGFnLFxuICAgIH0pO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxldGVIb29rQnlSdW5NYXJrZXJGaWxlKFxuICBiYXNlZGlyOiBzdHJpbmcsXG4gIGZpbGVJZDogc3RyaW5nXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgZGVsZXRlSlNPTihwYXRoLmpvaW4oYnlSdW5EaXIoYmFzZWRpciksIGAke2ZpbGVJZH0uanNvbmApKTtcbn1cblxuLy8gUGVyLXByb2Nlc3MgZW5zdXJlIGNhY2hlOyBvbmx5IHN1Y2Nlc3NmdWwgYmFja2ZpbGxzIGFyZSBjYWNoZWQuXG5jb25zdCBlbnN1cmVkQmFzZWRpcnMgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTx2b2lkPj4oKTtcblxuLyoqIEZvcmdldCBjb21wbGV0ZWQgYmFja2ZpbGxzIChkYXRhLWRpciByZXNldCAvIHRlc3RzKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldEhvb2tJbmRleEVuc3VyZUNhY2hlKCk6IHZvaWQge1xuICBlbnN1cmVkQmFzZWRpcnMuY2xlYXIoKTtcbn1cblxuLyoqXG4gKiBPbmUtdGltZSBiYWNrZmlsbCBvZiB0aGUgaW5kZXhlcyBmb3IgZGF0YSBkaXJlY3RvcmllcyBjcmVhdGVkIGJlZm9yZVxuICogdGhleSBleGlzdGVkIOKAlCBhIHNpbmdsZSBmdWxsIHNjYW4sIGd1YXJkZWQgYnkgYSBjb21wbGV0aW9uIG1hcmtlci5cbiAqIENvbmN1cnJlbnQgYmFja2ZpbGxzIGFyZSBzYWZlOiBhbGwgd3JpdGVzIGFyZSBpZGVtcG90ZW50XG4gKiBgd3JpdGVFeGNsdXNpdmVgIGNhbGxzIHdpdGggYnl0ZS1pZGVudGljYWwgY29udGVudC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVuc3VyZUhvb2tJbmRleGVzKGJhc2VkaXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBrZXkgPSBwYXRoLnJlc29sdmUoYmFzZWRpcik7XG4gIGxldCBwZW5kaW5nID0gZW5zdXJlZEJhc2VkaXJzLmdldChrZXkpO1xuICBpZiAoIXBlbmRpbmcpIHtcbiAgICBwZW5kaW5nID0gZW5zdXJlSG9va0luZGV4ZXNJbXBsKGtleSkuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICBlbnN1cmVkQmFzZWRpcnMuZGVsZXRlKGtleSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9KTtcbiAgICBlbnN1cmVkQmFzZWRpcnMuc2V0KGtleSwgcGVuZGluZyk7XG4gIH1cbiAgcmV0dXJuIHBlbmRpbmc7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZvckVhY2hDb25jdXJyZW50PFQ+KFxuICBpdGVtczogVFtdLFxuICBjb25jdXJyZW5jeTogbnVtYmVyLFxuICBmbjogKGl0ZW06IFQpID0+IFByb21pc2U8dm9pZD5cbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKGxldCBzdGFydCA9IDA7IHN0YXJ0IDwgaXRlbXMubGVuZ3RoOyBzdGFydCArPSBjb25jdXJyZW5jeSkge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKGl0ZW1zLnNsaWNlKHN0YXJ0LCBzdGFydCArIGNvbmN1cnJlbmN5KS5tYXAoZm4pKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVIb29rSW5kZXhlc0ltcGwoYmFzZWRpcjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG1hcmtlclBhdGggPSBwYXRoLmpvaW4oYmFzZWRpciwgJ2hvb2tzJywgSU5ERVhfQ09NUExFVEVfTUFSS0VSKTtcbiAgdHJ5IHtcbiAgICBhd2FpdCBmcy5hY2Nlc3MobWFya2VyUGF0aCk7XG4gICAgcmV0dXJuO1xuICB9IGNhdGNoIHtcbiAgICAvLyBNYXJrZXIgYWJzZW50IOKAlCBiYWNrZmlsbCBiZWxvdy5cbiAgfVxuXG4gIGNvbnN0IGV2ZW50c0RpciA9IHBhdGguam9pbihiYXNlZGlyLCAnZXZlbnRzJyk7XG4gIGF3YWl0IGZvckVhY2hDb25jdXJyZW50KFxuICAgIGF3YWl0IGxpc3RKU09ORmlsZXMoZXZlbnRzRGlyKSxcbiAgICAzMixcbiAgICBhc3luYyAoZmlsZUlkKSA9PiB7XG4gICAgICBjb25zdCBldmVudCA9IGF3YWl0IHJlYWRFdmVudExlbmllbnQoXG4gICAgICAgIHBhdGguam9pbihldmVudHNEaXIsIGAke2ZpbGVJZH0uanNvbmApXG4gICAgICApO1xuICAgICAgaWYgKCFldmVudCB8fCBldmVudC5ldmVudFR5cGUgIT09ICdob29rX2NyZWF0ZWQnKSByZXR1cm47XG4gICAgICBpZiAodHlwZW9mIGV2ZW50LmNvcnJlbGF0aW9uSWQgIT09ICdzdHJpbmcnKSByZXR1cm47XG4gICAgICBjb25zdCB0b2tlbiA9IChldmVudC5ldmVudERhdGEgYXMgeyB0b2tlbj86IHVua25vd24gfSB8IHVuZGVmaW5lZCk/LnRva2VuO1xuICAgICAgaWYgKHR5cGVvZiB0b2tlbiAhPT0gJ3N0cmluZycpIHJldHVybjtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHdyaXRlSG9va0NyZWF0ZWRJbmRleEVudHJpZXMoXG4gICAgICAgICAgYmFzZWRpcixcbiAgICAgICAgICB0b2tlbixcbiAgICAgICAgICBldmVudC5ydW5JZCxcbiAgICAgICAgICBldmVudC5jb3JyZWxhdGlvbklkLFxuICAgICAgICAgIGV2ZW50LmV2ZW50SWQsXG4gICAgICAgICAgdGFnT2YoZmlsZUlkKVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIFVuc2FmZSBpZHMgY2Fubm90IGhhdmUgYmVlbiB3cml0dGVuIGJ5IHRoaXMgc3RvcmFnZSBsYXllcjsgc2tpcC5cbiAgICAgIH1cbiAgICB9XG4gICk7XG5cbiAgY29uc3QgaG9va3NEaXIgPSBwYXRoLmpvaW4oYmFzZWRpciwgJ2hvb2tzJyk7XG4gIGF3YWl0IGZvckVhY2hDb25jdXJyZW50KGF3YWl0IGxpc3RKU09ORmlsZXMoaG9va3NEaXIpLCAzMiwgYXN5bmMgKGZpbGVJZCkgPT4ge1xuICAgIGxldCBob29rOiB6LmluZmVyPHR5cGVvZiBIb29rU2NoZW1hPiB8IG51bGwgPSBudWxsO1xuICAgIHRyeSB7XG4gICAgICBob29rID0gYXdhaXQgcmVhZEpTT04ocGF0aC5qb2luKGhvb2tzRGlyLCBgJHtmaWxlSWR9Lmpzb25gKSwgSG9va1NjaGVtYSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICghKGVycm9yIGluc3RhbmNlb2YgU3ludGF4RXJyb3IgfHwgZXJyb3IgaW5zdGFuY2VvZiB6LlpvZEVycm9yKSkge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFob29rKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHdyaXRlSG9va0J5UnVuTWFya2VyKFxuICAgICAgICBiYXNlZGlyLFxuICAgICAgICBob29rLnJ1bklkLFxuICAgICAgICBob29rLmhvb2tJZCxcbiAgICAgICAgdGFnT2YoZmlsZUlkKVxuICAgICAgKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFVuc2FmZSBpZHMgY2Fubm90IGhhdmUgYmVlbiB3cml0dGVuIGJ5IHRoaXMgc3RvcmFnZSBsYXllcjsgc2tpcC5cbiAgICB9XG4gIH0pO1xuXG4gIGF3YWl0IHdyaXRlRXhjbHVzaXZlKG1hcmtlclBhdGgsICcnKTtcbn1cblxuLyoqXG4gKiBGaW5kIHRoZSBuZXdlc3QgdmlzaWJsZSBgaG9va19jcmVhdGVkYCBldmVudCBmb3IgYSB0b2tlbiBvciBob29rSWQuXG4gKiBFbnRyaWVzIGFyZSBpdGVyYXRlZCBuZXdlc3QtZmlyc3QgKGV2ZW50SWRzIGFyZSBVTElEcyk7IGRhbmdsaW5nIG9yXG4gKiBub24tbWF0Y2hpbmcgZW50cmllcyBhcmUgc2tpcHBlZC4gTGl2ZW5lc3MgaXMgdGhlIGNhbGxlcidzIGpvYi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpbmROZXdlc3RJbmRleGVkSG9va0NyZWF0ZWRFdmVudChcbiAgYmFzZWRpcjogc3RyaW5nLFxuICBpbmRleDogeyBraW5kOiAndG9rZW4nOyB0b2tlbjogc3RyaW5nIH0gfCB7IGtpbmQ6ICdpZCc7IGhvb2tJZDogc3RyaW5nIH0sXG4gIG1hdGNoZXM6IChldmVudDogRXZlbnQpID0+IGJvb2xlYW4sXG4gIHRhZz86IHN0cmluZ1xuKTogUHJvbWlzZTxFdmVudCB8IG51bGw+IHtcbiAgYXdhaXQgZW5zdXJlSG9va0luZGV4ZXMoYmFzZWRpcik7XG4gIGxldCBkaXI6IHN0cmluZztcbiAgdHJ5IHtcbiAgICBkaXIgPVxuICAgICAgaW5kZXgua2luZCA9PT0gJ3Rva2VuJ1xuICAgICAgICA/IHRva2VuSW5kZXhEaXIoYmFzZWRpciwgaW5kZXgudG9rZW4pXG4gICAgICAgIDogaWRJbmRleERpcihiYXNlZGlyLCBpbmRleC5ob29rSWQpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGVudHJ5SWRzID0gKGF3YWl0IGxpc3RKU09ORmlsZXMoZGlyKSlcbiAgICAuZmlsdGVyKChmaWxlSWQpID0+IGlzVmlzaWJsZVRvVGFnKGZpbGVJZCwgdGFnKSlcbiAgICAuc29ydCgoYSwgYikgPT4gc3RyaXBUYWcoYikubG9jYWxlQ29tcGFyZShzdHJpcFRhZyhhKSkpO1xuXG4gIGZvciAoY29uc3QgZW50cnlJZCBvZiBlbnRyeUlkcykge1xuICAgIGxldCBlbnRyeTogei5pbmZlcjx0eXBlb2YgSW5kZXhFbnRyeVNjaGVtYT4gfCBudWxsID0gbnVsbDtcbiAgICB0cnkge1xuICAgICAgZW50cnkgPSBhd2FpdCByZWFkSlNPTihcbiAgICAgICAgcGF0aC5qb2luKGRpciwgYCR7ZW50cnlJZH0uanNvbmApLFxuICAgICAgICBJbmRleEVudHJ5U2NoZW1hXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoIShlcnJvciBpbnN0YW5jZW9mIFN5bnRheEVycm9yIHx8IGVycm9yIGluc3RhbmNlb2Ygei5ab2RFcnJvcikpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICghZW50cnkpIGNvbnRpbnVlO1xuXG4gICAgY29uc3QgZXZlbnRJZCA9IHN0cmlwVGFnKGVudHJ5SWQpO1xuICAgIGxldCBldmVudFBhdGg6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgZXZlbnRQYXRoID0gdGFnZ2VkUGF0aChcbiAgICAgICAgYmFzZWRpcixcbiAgICAgICAgJ2V2ZW50cycsXG4gICAgICAgIGAke2VudHJ5LnJ1bklkfS0ke2V2ZW50SWR9YCxcbiAgICAgICAgdGFnT2YoZW50cnlJZClcbiAgICAgICk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgZXZlbnQgPSBhd2FpdCByZWFkRXZlbnRMZW5pZW50KGV2ZW50UGF0aCk7XG4gICAgaWYgKCFldmVudCkgY29udGludWU7XG4gICAgaWYgKGV2ZW50LmV2ZW50VHlwZSAhPT0gJ2hvb2tfY3JlYXRlZCcpIGNvbnRpbnVlO1xuICAgIGlmICh0eXBlb2YgZXZlbnQuY29ycmVsYXRpb25JZCAhPT0gJ3N0cmluZycpIGNvbnRpbnVlO1xuICAgIGlmICghbWF0Y2hlcyhldmVudCkpIGNvbnRpbnVlO1xuICAgIHJldHVybiBldmVudDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cbiJdfQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-storage.d.ts","sourceRoot":"","sources":["../../src/storage/hooks-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,IAAI,EAIJ,OAAO,EACR,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks-storage.d.ts","sourceRoot":"","sources":["../../src/storage/hooks-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,IAAI,EAIJ,OAAO,EACR,MAAM,iBAAiB,CAAC;AA+JzB,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAQtB;AAgBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAmIlB;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAsCf"}
|