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.
- package/README.md +1 -2
- package/build/configuration-types.js +11 -0
- package/build/configuration.js +122 -1
- package/build/database/advisory-lock-backend-policy.js +204 -0
- package/build/database/advisory-lock-file-backend.js +348 -0
- package/build/database/advisory-lock-runner.js +239 -16
- package/build/environment-handlers/base.js +13 -0
- package/build/environment-handlers/node.js +11 -0
- package/build/http-server/server-lock.js +21 -115
- package/build/src/configuration-types.d.ts +31 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +11 -1
- package/build/src/configuration.d.ts +88 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +112 -2
- package/build/src/database/advisory-lock-backend-policy.d.ts +145 -0
- package/build/src/database/advisory-lock-backend-policy.d.ts.map +1 -0
- package/build/src/database/advisory-lock-backend-policy.js +184 -0
- package/build/src/database/advisory-lock-file-backend.d.ts +194 -0
- package/build/src/database/advisory-lock-file-backend.d.ts.map +1 -0
- package/build/src/database/advisory-lock-file-backend.js +313 -0
- package/build/src/database/advisory-lock-runner.d.ts +116 -15
- package/build/src/database/advisory-lock-runner.d.ts.map +1 -1
- package/build/src/database/advisory-lock-runner.js +190 -17
- package/build/src/environment-handlers/base.d.ts +14 -0
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +13 -1
- package/build/src/environment-handlers/node.d.ts +11 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +11 -1
- package/build/src/http-server/server-lock.d.ts +13 -37
- package/build/src/http-server/server-lock.d.ts.map +1 -1
- package/build/src/http-server/server-lock.js +22 -109
- package/package.json +1 -1
- package/src/configuration-types.js +11 -0
- package/src/configuration.js +122 -1
- package/src/database/advisory-lock-backend-policy.js +204 -0
- package/src/database/advisory-lock-file-backend.js +348 -0
- package/src/database/advisory-lock-runner.js +239 -16
- package/src/environment-handlers/base.js +13 -0
- package/src/environment-handlers/node.js +11 -0
- package/src/http-server/server-lock.js +21 -115
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
export type AdvisoryLockTier = "process-local" | "file" | "driver-native" | "lock-server";
|
|
2
|
+
export type AdvisoryLockBackendPolicyEntry = {
|
|
3
|
+
/**
|
|
4
|
+
* - Lock name or `*`-suffixed glob pattern (e.g. `background_jobs:*`).
|
|
5
|
+
*/
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* - Weakest tier this name may ever be served by. Defaults to `driver-native` (default-deny).
|
|
9
|
+
*/
|
|
10
|
+
minTier?: AdvisoryLockTier;
|
|
11
|
+
/**
|
|
12
|
+
* - Explicit whitelist of servable tiers. Defaults to every tier at or above `minTier`.
|
|
13
|
+
*/
|
|
14
|
+
allowedTiers?: AdvisoryLockTier[];
|
|
15
|
+
/**
|
|
16
|
+
* - Tier used when available; falling below it triggers the fallback report (§3). Defaults to `driver-native`.
|
|
17
|
+
*/
|
|
18
|
+
preferredTier?: AdvisoryLockTier;
|
|
19
|
+
};
|
|
20
|
+
export type ResolvedAdvisoryLockBackendPolicy = {
|
|
21
|
+
/**
|
|
22
|
+
* - Weakest tier this name may be served by.
|
|
23
|
+
*/
|
|
24
|
+
minTier: AdvisoryLockTier;
|
|
25
|
+
/**
|
|
26
|
+
* - Tiers that may serve this name (minimum-closed).
|
|
27
|
+
*/
|
|
28
|
+
allowedTiers: AdvisoryLockTier[];
|
|
29
|
+
/**
|
|
30
|
+
* - Tier preferred when available.
|
|
31
|
+
*/
|
|
32
|
+
preferredTier: AdvisoryLockTier;
|
|
33
|
+
/**
|
|
34
|
+
* - The matched configuration entry, or null for the default policy.
|
|
35
|
+
*/
|
|
36
|
+
entry: AdvisoryLockBackendPolicyEntry | null;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Advisory-lock backend tiers (STC-210 design, `docs/advisory-lock-backends.md` §1/§9).
|
|
40
|
+
* `process-local` and `file` are host-local; `driver-native` and `lock-server` are
|
|
41
|
+
* cross-host. Tier strength order (strongest first):
|
|
42
|
+
* `lock-server` ≡ `driver-native` > `file` > `process-local`.
|
|
43
|
+
* @typedef {"process-local" | "file" | "driver-native" | "lock-server"} AdvisoryLockTier
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* One per-lock-name backend policy entry as declared in configuration (§5).
|
|
47
|
+
* @typedef {object} AdvisoryLockBackendPolicyEntry
|
|
48
|
+
* @property {string} name - Lock name or `*`-suffixed glob pattern (e.g. `background_jobs:*`).
|
|
49
|
+
* @property {AdvisoryLockTier} [minTier] - Weakest tier this name may ever be served by. Defaults to `driver-native` (default-deny).
|
|
50
|
+
* @property {AdvisoryLockTier[]} [allowedTiers] - Explicit whitelist of servable tiers. Defaults to every tier at or above `minTier`.
|
|
51
|
+
* @property {AdvisoryLockTier} [preferredTier] - Tier used when available; falling below it triggers the fallback report (§3). Defaults to `driver-native`.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Policy resolved for one concrete lock name, with tier gaps already closed:
|
|
55
|
+
* `allowedTiers` always contains every tier at or above `minTier`, so a
|
|
56
|
+
* cross-host-minimum name can never be served by `file` or `process-local`.
|
|
57
|
+
* @typedef {object} ResolvedAdvisoryLockBackendPolicy
|
|
58
|
+
* @property {AdvisoryLockTier} minTier - Weakest tier this name may be served by.
|
|
59
|
+
* @property {AdvisoryLockTier[]} allowedTiers - Tiers that may serve this name (minimum-closed).
|
|
60
|
+
* @property {AdvisoryLockTier} preferredTier - Tier preferred when available.
|
|
61
|
+
* @property {AdvisoryLockBackendPolicyEntry | null} entry - The matched configuration entry, or null for the default policy.
|
|
62
|
+
*/
|
|
63
|
+
/**
|
|
64
|
+
* Thrown when an acquisition would have to be served by a tier below the
|
|
65
|
+
* lock name's declared minimum tier. Fail-closed refusal (§9): the name is
|
|
66
|
+
* never served by the weaker tier, and the refusal is reported on the
|
|
67
|
+
* framework-error channel as `advisory-lock-min-tier-refused`.
|
|
68
|
+
*/
|
|
69
|
+
export declare class AdvisoryLockMinTierRefusedError extends Error {
|
|
70
|
+
lockName: string;
|
|
71
|
+
requestedBackend: AdvisoryLockTier;
|
|
72
|
+
minTier: AdvisoryLockTier;
|
|
73
|
+
/**
|
|
74
|
+
* Runs constructor.
|
|
75
|
+
* @param {string} message - Error message.
|
|
76
|
+
* @param {{lockName: string, requestedBackend: AdvisoryLockTier, minTier: AdvisoryLockTier}} args - Refusal details.
|
|
77
|
+
*/
|
|
78
|
+
constructor(message: string, { lockName, requestedBackend, minTier }: {
|
|
79
|
+
lockName: string;
|
|
80
|
+
requestedBackend: AdvisoryLockTier;
|
|
81
|
+
minTier: AdvisoryLockTier;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Thrown when no enabled backend that satisfies the lock name's minimum tier
|
|
86
|
+
* is available (§9). Distinct from `AdvisoryLockTimeoutError` (a backend
|
|
87
|
+
* served the wait but the holder never released).
|
|
88
|
+
*/
|
|
89
|
+
export declare class AdvisoryLockBackendUnavailableError extends Error {
|
|
90
|
+
lockName: string;
|
|
91
|
+
minTier: AdvisoryLockTier;
|
|
92
|
+
reasons: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Runs constructor.
|
|
95
|
+
* @param {string} message - Error message.
|
|
96
|
+
* @param {{lockName: string, minTier: AdvisoryLockTier, reasons: string[]}} args - Unavailability details.
|
|
97
|
+
*/
|
|
98
|
+
constructor(message: string, { lockName, minTier, reasons }: {
|
|
99
|
+
lockName: string;
|
|
100
|
+
minTier: AdvisoryLockTier;
|
|
101
|
+
reasons: string[];
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Runs tier rank.
|
|
106
|
+
* @param {AdvisoryLockTier} tier - Tier to rank.
|
|
107
|
+
* @returns {number} - Strength rank (higher is stronger).
|
|
108
|
+
*/
|
|
109
|
+
export declare function advisoryLockTierRank(tier: AdvisoryLockTier): number;
|
|
110
|
+
/**
|
|
111
|
+
* Runs tier is at least as strong as.
|
|
112
|
+
* @param {AdvisoryLockTier} tier - Candidate serving tier.
|
|
113
|
+
* @param {AdvisoryLockTier} minimum - Required minimum tier.
|
|
114
|
+
* @returns {boolean} - Whether `tier` satisfies the minimum.
|
|
115
|
+
*/
|
|
116
|
+
export declare function advisoryLockTierSatisfies(tier: AdvisoryLockTier, minimum: AdvisoryLockTier): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Resolves the effective backend policy for one concrete lock name:
|
|
119
|
+
* longest-prefix glob match over the configured entries (exact names win),
|
|
120
|
+
* default-deny for undeclared names (`minTier: driver-native`,
|
|
121
|
+
* `preferredTier: driver-native`), and `allowedTiers` closed upward so a
|
|
122
|
+
* cross-host minimum can never be served by a host-local tier.
|
|
123
|
+
* @param {string} lockName - Concrete lock name.
|
|
124
|
+
* @param {AdvisoryLockBackendPolicyEntry[] | undefined} policy - Configured policy entries.
|
|
125
|
+
* @returns {ResolvedAdvisoryLockBackendPolicy} - Resolved policy.
|
|
126
|
+
*/
|
|
127
|
+
export declare function resolveAdvisoryLockBackendPolicy(lockName: string, policy: AdvisoryLockBackendPolicyEntry[] | undefined): ResolvedAdvisoryLockBackendPolicy;
|
|
128
|
+
/**
|
|
129
|
+
* Refuses a downgrade below the lock name's minimum tier before any contact
|
|
130
|
+
* with the weaker backend (§9), reporting the refusal on the framework-error
|
|
131
|
+
* channel so a silent downgrade is impossible to hide.
|
|
132
|
+
* @param {object} args - Refusal args.
|
|
133
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration owning the error channel.
|
|
134
|
+
* @param {string} args.lockName - Lock name.
|
|
135
|
+
* @param {AdvisoryLockTier} args.requestedBackend - Tier the acquisition would fall to.
|
|
136
|
+
* @param {AdvisoryLockTier} args.minTier - Declared minimum tier.
|
|
137
|
+
* @returns {never} - Always throws.
|
|
138
|
+
*/
|
|
139
|
+
export declare function refuseAdvisoryLockTierBelowMinimum({ configuration, lockName, requestedBackend, minTier }: {
|
|
140
|
+
configuration: import("../configuration.js").default;
|
|
141
|
+
lockName: string;
|
|
142
|
+
requestedBackend: AdvisoryLockTier;
|
|
143
|
+
minTier: AdvisoryLockTier;
|
|
144
|
+
}): never;
|
|
145
|
+
//# sourceMappingURL=advisory-lock-backend-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisory-lock-backend-policy.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-backend-policy.js"],"names":[],"mappings":"AAOG,YAAsE,gBAAgB,GAA5E,eAAe,GAAG,MAAM,GAAG,eAAe,GAAG,aAAa,CAAkB;AAItF,YAAkB,8BAA8B,GAChD;;;;IAAmB,IAAI,EAAZ,MAAM,CACjB;;;;IAA8B,OAAO,AAArC,CACA,EADW,gBAAgB,CAC3B;;;;IAAgC,YAAY,AAA5C,CACA,EADW,gBAAgB,EAAE,CAC7B;;;;IAA8B,aAAa,AAA3C,CACF,EADa,gBAAgB,CAC7B;CAAA,CAAA;AAKE,YAAkB,iCAAiC,GACnD;;;;IAA6B,OAAO,EAAzB,gBAAgB,CAC3B;;;;IAA+B,YAAY,EAAhC,gBAAgB,EAAE,CAC7B;;;;IAA6B,aAAa,EAA/B,gBAAgB,CAC3B;;;;IAAkD,KAAK,EAA5C,8BAA8B,GAAG,IAAI,CAClD;CAAA,CAAA;AAxBD;;;;;;GAMG;AACH;;;;;;;GAOG;AACH;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,qBAAa,+BAAgC,SAAQ,KAAK;IASjD,QAAQ;IACR,gBAAgB;IAChB,OAAO;IAVd;;;;OAIG;IACH,YAAY,OAAO,EAHR,MAGQ,EAAE,EAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAC,EAF/C;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAA;KAEjC,EAMzD;CACF;AAED;;;;GAIG;AACH,qBAAa,mCAAoC,SAAQ,KAAK;IASrD,QAAQ;IACR,OAAO;IACP,OAAO;IAVd;;;;OAIG;IACH,YAAY,OAAO,EAHR,MAGQ,EAAE,EAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAC,EAFtC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAEzB,EAMhD;CACF;AAgBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAH9B,gBAG8B,GAF5B,MAAM,CAQlB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAJnC,gBAImC,EAAE,OAAO,EAH5C,gBAG4C,GAF1C,OAAO,CAInB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAJ9C,MAI8C,EAAE,MAAM,EAHtD,8BAA8B,EAAE,GAAG,SAGmB,GAFpD,iCAAiC,CAsB7C;AAiCD;;;;;;;;;;GAUG;AACH,wBAAgB,kCAAkC,CAAC,EAAC,aAAa,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAC,EANpG;IAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO,CAC7C;IAAqB,QAAQ,EAArB,MAAM,CACd;IAA+B,gBAAgB,EAAvC,gBAAgB,CACxB;IAA+B,OAAO,EAA9B,gBAAgB,CACxB;CAEoG,GAF1F,KAAK,CAyBjB"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Advisory-lock backend tiers (STC-210 design, `docs/advisory-lock-backends.md` §1/§9).
|
|
4
|
+
* `process-local` and `file` are host-local; `driver-native` and `lock-server` are
|
|
5
|
+
* cross-host. Tier strength order (strongest first):
|
|
6
|
+
* `lock-server` ≡ `driver-native` > `file` > `process-local`.
|
|
7
|
+
* @typedef {"process-local" | "file" | "driver-native" | "lock-server"} AdvisoryLockTier
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* One per-lock-name backend policy entry as declared in configuration (§5).
|
|
11
|
+
* @typedef {object} AdvisoryLockBackendPolicyEntry
|
|
12
|
+
* @property {string} name - Lock name or `*`-suffixed glob pattern (e.g. `background_jobs:*`).
|
|
13
|
+
* @property {AdvisoryLockTier} [minTier] - Weakest tier this name may ever be served by. Defaults to `driver-native` (default-deny).
|
|
14
|
+
* @property {AdvisoryLockTier[]} [allowedTiers] - Explicit whitelist of servable tiers. Defaults to every tier at or above `minTier`.
|
|
15
|
+
* @property {AdvisoryLockTier} [preferredTier] - Tier used when available; falling below it triggers the fallback report (§3). Defaults to `driver-native`.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Policy resolved for one concrete lock name, with tier gaps already closed:
|
|
19
|
+
* `allowedTiers` always contains every tier at or above `minTier`, so a
|
|
20
|
+
* cross-host-minimum name can never be served by `file` or `process-local`.
|
|
21
|
+
* @typedef {object} ResolvedAdvisoryLockBackendPolicy
|
|
22
|
+
* @property {AdvisoryLockTier} minTier - Weakest tier this name may be served by.
|
|
23
|
+
* @property {AdvisoryLockTier[]} allowedTiers - Tiers that may serve this name (minimum-closed).
|
|
24
|
+
* @property {AdvisoryLockTier} preferredTier - Tier preferred when available.
|
|
25
|
+
* @property {AdvisoryLockBackendPolicyEntry | null} entry - The matched configuration entry, or null for the default policy.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when an acquisition would have to be served by a tier below the
|
|
29
|
+
* lock name's declared minimum tier. Fail-closed refusal (§9): the name is
|
|
30
|
+
* never served by the weaker tier, and the refusal is reported on the
|
|
31
|
+
* framework-error channel as `advisory-lock-min-tier-refused`.
|
|
32
|
+
*/
|
|
33
|
+
export class AdvisoryLockMinTierRefusedError extends Error {
|
|
34
|
+
/**
|
|
35
|
+
* Runs constructor.
|
|
36
|
+
* @param {string} message - Error message.
|
|
37
|
+
* @param {{lockName: string, requestedBackend: AdvisoryLockTier, minTier: AdvisoryLockTier}} args - Refusal details.
|
|
38
|
+
*/
|
|
39
|
+
constructor(message, { lockName, requestedBackend, minTier }) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "AdvisoryLockMinTierRefusedError";
|
|
42
|
+
this.lockName = lockName;
|
|
43
|
+
this.requestedBackend = requestedBackend;
|
|
44
|
+
this.minTier = minTier;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Thrown when no enabled backend that satisfies the lock name's minimum tier
|
|
49
|
+
* is available (§9). Distinct from `AdvisoryLockTimeoutError` (a backend
|
|
50
|
+
* served the wait but the holder never released).
|
|
51
|
+
*/
|
|
52
|
+
export class AdvisoryLockBackendUnavailableError extends Error {
|
|
53
|
+
/**
|
|
54
|
+
* Runs constructor.
|
|
55
|
+
* @param {string} message - Error message.
|
|
56
|
+
* @param {{lockName: string, minTier: AdvisoryLockTier, reasons: string[]}} args - Unavailability details.
|
|
57
|
+
*/
|
|
58
|
+
constructor(message, { lockName, minTier, reasons }) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = "AdvisoryLockBackendUnavailableError";
|
|
61
|
+
this.lockName = lockName;
|
|
62
|
+
this.minTier = minTier;
|
|
63
|
+
this.reasons = reasons;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Tier strength ranks (§9): higher rank is stronger. `lock-server` and
|
|
68
|
+
* `driver-native` are both cross-host and rank equal.
|
|
69
|
+
* @type {Record<AdvisoryLockTier, number>} */
|
|
70
|
+
const TIER_RANKS = {
|
|
71
|
+
"driver-native": 2,
|
|
72
|
+
file: 1,
|
|
73
|
+
"lock-server": 3,
|
|
74
|
+
"process-local": 0
|
|
75
|
+
};
|
|
76
|
+
/** All tiers ordered strongest-first. */
|
|
77
|
+
const TIERS_STRONGEST_FIRST = /** @type {AdvisoryLockTier[]} */ (["lock-server", "driver-native", "file", "process-local"]);
|
|
78
|
+
/**
|
|
79
|
+
* Runs tier rank.
|
|
80
|
+
* @param {AdvisoryLockTier} tier - Tier to rank.
|
|
81
|
+
* @returns {number} - Strength rank (higher is stronger).
|
|
82
|
+
*/
|
|
83
|
+
export function advisoryLockTierRank(tier) {
|
|
84
|
+
const rank = TIER_RANKS[tier];
|
|
85
|
+
if (rank === undefined)
|
|
86
|
+
throw new Error(`Unknown advisory-lock tier ${JSON.stringify(String(tier))}`);
|
|
87
|
+
return rank;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Runs tier is at least as strong as.
|
|
91
|
+
* @param {AdvisoryLockTier} tier - Candidate serving tier.
|
|
92
|
+
* @param {AdvisoryLockTier} minimum - Required minimum tier.
|
|
93
|
+
* @returns {boolean} - Whether `tier` satisfies the minimum.
|
|
94
|
+
*/
|
|
95
|
+
export function advisoryLockTierSatisfies(tier, minimum) {
|
|
96
|
+
return advisoryLockTierRank(tier) >= advisoryLockTierRank(minimum);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolves the effective backend policy for one concrete lock name:
|
|
100
|
+
* longest-prefix glob match over the configured entries (exact names win),
|
|
101
|
+
* default-deny for undeclared names (`minTier: driver-native`,
|
|
102
|
+
* `preferredTier: driver-native`), and `allowedTiers` closed upward so a
|
|
103
|
+
* cross-host minimum can never be served by a host-local tier.
|
|
104
|
+
* @param {string} lockName - Concrete lock name.
|
|
105
|
+
* @param {AdvisoryLockBackendPolicyEntry[] | undefined} policy - Configured policy entries.
|
|
106
|
+
* @returns {ResolvedAdvisoryLockBackendPolicy} - Resolved policy.
|
|
107
|
+
*/
|
|
108
|
+
export function resolveAdvisoryLockBackendPolicy(lockName, policy) {
|
|
109
|
+
const entry = matchAdvisoryLockPolicyEntry(lockName, policy);
|
|
110
|
+
const minTier = entry?.minTier ?? "driver-native";
|
|
111
|
+
const preferredTier = entry?.preferredTier ?? "driver-native";
|
|
112
|
+
// §9: eligibility filters to tier strength >= minTier even when a weaker
|
|
113
|
+
// tier was declared in `allowedTiers` — a cross-host minimum can never be
|
|
114
|
+
// served by `file` or `process-local`. A `preferredTier` below the minimum
|
|
115
|
+
// stays visible here so the runner can refuse it loudly before contacting
|
|
116
|
+
// the weaker backend.
|
|
117
|
+
const declaredAllowed = entry?.allowedTiers;
|
|
118
|
+
const allowedTiers = TIERS_STRONGEST_FIRST.filter((tier) => {
|
|
119
|
+
if (!advisoryLockTierSatisfies(tier, minTier))
|
|
120
|
+
return false;
|
|
121
|
+
if (!Array.isArray(declaredAllowed))
|
|
122
|
+
return true;
|
|
123
|
+
return declaredAllowed.includes(tier);
|
|
124
|
+
});
|
|
125
|
+
return { allowedTiers, entry: entry ?? null, minTier, preferredTier };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Matches one policy entry for a lock name: exact `name` matches win;
|
|
129
|
+
* otherwise the longest `*`-suffixed prefix pattern wins.
|
|
130
|
+
* @param {string} lockName - Concrete lock name.
|
|
131
|
+
* @param {AdvisoryLockBackendPolicyEntry[] | undefined} policy - Configured policy entries.
|
|
132
|
+
* @returns {AdvisoryLockBackendPolicyEntry | null} - Matched entry or null.
|
|
133
|
+
*/
|
|
134
|
+
function matchAdvisoryLockPolicyEntry(lockName, policy) {
|
|
135
|
+
if (!Array.isArray(policy))
|
|
136
|
+
return null;
|
|
137
|
+
let bestPrefixMatch = null;
|
|
138
|
+
let bestPrefixLength = -1;
|
|
139
|
+
for (const entry of policy) {
|
|
140
|
+
if (typeof entry?.name !== "string")
|
|
141
|
+
continue;
|
|
142
|
+
if (entry.name === lockName)
|
|
143
|
+
return entry;
|
|
144
|
+
if (entry.name.endsWith("*")) {
|
|
145
|
+
const prefix = entry.name.slice(0, -1);
|
|
146
|
+
if (lockName.startsWith(prefix) && prefix.length > bestPrefixLength) {
|
|
147
|
+
bestPrefixMatch = entry;
|
|
148
|
+
bestPrefixLength = prefix.length;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return bestPrefixMatch;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Refuses a downgrade below the lock name's minimum tier before any contact
|
|
156
|
+
* with the weaker backend (§9), reporting the refusal on the framework-error
|
|
157
|
+
* channel so a silent downgrade is impossible to hide.
|
|
158
|
+
* @param {object} args - Refusal args.
|
|
159
|
+
* @param {import("../configuration.js").default} args.configuration - Configuration owning the error channel.
|
|
160
|
+
* @param {string} args.lockName - Lock name.
|
|
161
|
+
* @param {AdvisoryLockTier} args.requestedBackend - Tier the acquisition would fall to.
|
|
162
|
+
* @param {AdvisoryLockTier} args.minTier - Declared minimum tier.
|
|
163
|
+
* @returns {never} - Always throws.
|
|
164
|
+
*/
|
|
165
|
+
export function refuseAdvisoryLockTierBelowMinimum({ configuration, lockName, requestedBackend, minTier }) {
|
|
166
|
+
const error = new AdvisoryLockMinTierRefusedError(`Advisory lock ${JSON.stringify(lockName)} requires minimum tier ${JSON.stringify(minTier)}; the ${JSON.stringify(requestedBackend)} tier is refused. Enable a cross-host backend or declare minTier: "file" for this lock name (single-host deployments only).`, { lockName, minTier, requestedBackend });
|
|
167
|
+
configuration.getErrorEvents().emit("framework-error", {
|
|
168
|
+
context: "advisory-lock-min-tier-refused",
|
|
169
|
+
error,
|
|
170
|
+
lockName,
|
|
171
|
+
minTier,
|
|
172
|
+
requestedBackend
|
|
173
|
+
});
|
|
174
|
+
configuration.getErrorEvents().emit("all-error", {
|
|
175
|
+
context: "advisory-lock-min-tier-refused",
|
|
176
|
+
error,
|
|
177
|
+
errorType: "framework-error",
|
|
178
|
+
lockName,
|
|
179
|
+
minTier,
|
|
180
|
+
requestedBackend
|
|
181
|
+
});
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWR2aXNvcnktbG9jay1iYWNrZW5kLXBvbGljeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kYXRhYmFzZS9hZHZpc29yeS1sb2NrLWJhY2tlbmQtcG9saWN5LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWjs7Ozs7O0dBTUc7QUFDSDs7Ozs7OztHQU9HO0FBQ0g7Ozs7Ozs7OztHQVNHO0FBRUg7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sK0JBQWdDLFNBQVEsS0FBSztJQUN4RDs7OztPQUlHO0lBQ0gsWUFBWSxPQUFPLEVBQUUsRUFBQyxRQUFRLEVBQUUsZ0JBQWdCLEVBQUUsT0FBTyxFQUFDO1FBQ3hELEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUNkLElBQUksQ0FBQyxJQUFJLEdBQUcsaUNBQWlDLENBQUE7UUFDN0MsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUE7UUFDeEIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO1FBQ3hDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO0lBQ3hCLENBQUM7Q0FDRjtBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sbUNBQW9DLFNBQVEsS0FBSztJQUM1RDs7OztPQUlHO0lBQ0gsWUFBWSxPQUFPLEVBQUUsRUFBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBQztRQUMvQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDZCxJQUFJLENBQUMsSUFBSSxHQUFHLHFDQUFxQyxDQUFBO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFBO1FBQ3hCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO1FBQ3RCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO0lBQ3hCLENBQUM7Q0FDRjtBQUVEOzs7OENBRzhDO0FBQzlDLE1BQU0sVUFBVSxHQUFHO0lBQ2pCLGVBQWUsRUFBRSxDQUFDO0lBQ2xC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LEdBQUcsS0FBSyxDQUFBO2dCQUN2QixnQkFBZ0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFBO1lBQ2xDLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sZUFBZSxDQUFBO0FBQ3hCLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxVQUFVLGtDQUFrQyxDQUFDLEVBQUMsYUFBYSxFQUFFLFFBQVEsRUFBRSxnQkFBZ0IsRUFBRSxPQUFPLEVBQUM7SUFDckcsTUFBTSxLQUFLLEdBQUcsSUFBSSwrQkFBK0IsQ0FDL0MsaUJBQWlCLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLDBCQUEwQixJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsNkhBQTZILEVBQ2hRLEVBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBQyxDQUN0QyxDQUFBO0lBRUQsYUFBYSxDQUFDLGNBQWMsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRTtRQUNyRCxPQUFPLEVBQUUsZ0NBQWdDO1FBQ3pDLEtBQUs7UUFDTCxRQUFRO1FBQ1IsT0FBTztRQUNQLGdCQUFnQjtLQUNqQixDQUFDLENBQUE7SUFDRixhQUFhLENBQUMsY0FBYyxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRTtRQUMvQyxPQUFPLEVBQUUsZ0NBQWdDO1FBQ3pDLEtBQUs7UUFDTCxTQUFTLEVBQUUsaUJBQWlCO1FBQzVCLFFBQVE7UUFDUixPQUFPO1FBQ1AsZ0JBQWdCO0tBQ2pCLENBQUMsQ0FBQTtJQUVGLE1BQU0sS0FBSyxDQUFBO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG4vKipcbiAqIEFkdmlzb3J5LWxvY2sgYmFja2VuZCB0aWVycyAoU1RDLTIxMCBkZXNpZ24sIGBkb2NzL2Fkdmlzb3J5LWxvY2stYmFja2VuZHMubWRgIMKnMS/CpzkpLlxuICogYHByb2Nlc3MtbG9jYWxgIGFuZCBgZmlsZWAgYXJlIGhvc3QtbG9jYWw7IGBkcml2ZXItbmF0aXZlYCBhbmQgYGxvY2stc2VydmVyYCBhcmVcbiAqIGNyb3NzLWhvc3QuIFRpZXIgc3RyZW5ndGggb3JkZXIgKHN0cm9uZ2VzdCBmaXJzdCk6XG4gKiBgbG9jay1zZXJ2ZXJgIOKJoSBgZHJpdmVyLW5hdGl2ZWAgPiBgZmlsZWAgPiBgcHJvY2Vzcy1sb2NhbGAuXG4gKiBAdHlwZWRlZiB7XCJwcm9jZXNzLWxvY2FsXCIgfCBcImZpbGVcIiB8IFwiZHJpdmVyLW5hdGl2ZVwiIHwgXCJsb2NrLXNlcnZlclwifSBBZHZpc29yeUxvY2tUaWVyXG4gKi9cbi8qKlxuICogT25lIHBlci1sb2NrLW5hbWUgYmFja2VuZCBwb2xpY3kgZW50cnkgYXMgZGVjbGFyZWQgaW4gY29uZmlndXJhdGlvbiAowqc1KS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IEFkdmlzb3J5TG9ja0JhY2tlbmRQb2xpY3lFbnRyeVxuICogQHByb3BlcnR5IHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUgb3IgYCpgLXN1ZmZpeGVkIGdsb2IgcGF0dGVybiAoZS5nLiBgYmFja2dyb3VuZF9qb2JzOipgKS5cbiAqIEBwcm9wZXJ0eSB7QWR2aXNvcnlMb2NrVGllcn0gW21pblRpZXJdIC0gV2Vha2VzdCB0aWVyIHRoaXMgbmFtZSBtYXkgZXZlciBiZSBzZXJ2ZWQgYnkuIERlZmF1bHRzIHRvIGBkcml2ZXItbmF0aXZlYCAoZGVmYXVsdC1kZW55KS5cbiAqIEBwcm9wZXJ0eSB7QWR2aXNvcnlMb2NrVGllcltdfSBbYWxsb3dlZFRpZXJzXSAtIEV4cGxpY2l0IHdoaXRlbGlzdCBvZiBzZXJ2YWJsZSB0aWVycy4gRGVmYXVsdHMgdG8gZXZlcnkgdGllciBhdCBvciBhYm92ZSBgbWluVGllcmAuXG4gKiBAcHJvcGVydHkge0Fkdmlzb3J5TG9ja1RpZXJ9IFtwcmVmZXJyZWRUaWVyXSAtIFRpZXIgdXNlZCB3aGVuIGF2YWlsYWJsZTsgZmFsbGluZyBiZWxvdyBpdCB0cmlnZ2VycyB0aGUgZmFsbGJhY2sgcmVwb3J0ICjCpzMpLiBEZWZhdWx0cyB0byBgZHJpdmVyLW5hdGl2ZWAuXG4gKi9cbi8qKlxuICogUG9saWN5IHJlc29sdmVkIGZvciBvbmUgY29uY3JldGUgbG9jayBuYW1lLCB3aXRoIHRpZXIgZ2FwcyBhbHJlYWR5IGNsb3NlZDpcbiAqIGBhbGxvd2VkVGllcnNgIGFsd2F5cyBjb250YWlucyBldmVyeSB0aWVyIGF0IG9yIGFib3ZlIGBtaW5UaWVyYCwgc28gYVxuICogY3Jvc3MtaG9zdC1taW5pbXVtIG5hbWUgY2FuIG5ldmVyIGJlIHNlcnZlZCBieSBgZmlsZWAgb3IgYHByb2Nlc3MtbG9jYWxgLlxuICogQHR5cGVkZWYge29iamVjdH0gUmVzb2x2ZWRBZHZpc29yeUxvY2tCYWNrZW5kUG9saWN5XG4gKiBAcHJvcGVydHkge0Fkdmlzb3J5TG9ja1RpZXJ9IG1pblRpZXIgLSBXZWFrZXN0IHRpZXIgdGhpcyBuYW1lIG1heSBiZSBzZXJ2ZWQgYnkuXG4gKiBAcHJvcGVydHkge0Fkdmlzb3J5TG9ja1RpZXJbXX0gYWxsb3dlZFRpZXJzIC0gVGllcnMgdGhhdCBtYXkgc2VydmUgdGhpcyBuYW1lIChtaW5pbXVtLWNsb3NlZCkuXG4gKiBAcHJvcGVydHkge0Fkdmlzb3J5TG9ja1RpZXJ9IHByZWZlcnJlZFRpZXIgLSBUaWVyIHByZWZlcnJlZCB3aGVuIGF2YWlsYWJsZS5cbiAqIEBwcm9wZXJ0eSB7QWR2aXNvcnlMb2NrQmFja2VuZFBvbGljeUVudHJ5IHwgbnVsbH0gZW50cnkgLSBUaGUgbWF0Y2hlZCBjb25maWd1cmF0aW9uIGVudHJ5LCBvciBudWxsIGZvciB0aGUgZGVmYXVsdCBwb2xpY3kuXG4gKi9cblxuLyoqXG4gKiBUaHJvd24gd2hlbiBhbiBhY3F1aXNpdGlvbiB3b3VsZCBoYXZlIHRvIGJlIHNlcnZlZCBieSBhIHRpZXIgYmVsb3cgdGhlXG4gKiBsb2NrIG5hbWUncyBkZWNsYXJlZCBtaW5pbXVtIHRpZXIuIEZhaWwtY2xvc2VkIHJlZnVzYWwgKMKnOSk6IHRoZSBuYW1lIGlzXG4gKiBuZXZlciBzZXJ2ZWQgYnkgdGhlIHdlYWtlciB0aWVyLCBhbmQgdGhlIHJlZnVzYWwgaXMgcmVwb3J0ZWQgb24gdGhlXG4gKiBmcmFtZXdvcmstZXJyb3IgY2hhbm5lbCBhcyBgYWR2aXNvcnktbG9jay1taW4tdGllci1yZWZ1c2VkYC5cbiAqL1xuZXhwb3J0IGNsYXNzIEFkdmlzb3J5TG9ja01pblRpZXJSZWZ1c2VkRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIEVycm9yIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSB7e2xvY2tOYW1lOiBzdHJpbmcsIHJlcXVlc3RlZEJhY2tlbmQ6IEFkdmlzb3J5TG9ja1RpZXIsIG1pblRpZXI6IEFkdmlzb3J5TG9ja1RpZXJ9fSBhcmdzIC0gUmVmdXNhbCBkZXRhaWxzLlxuICAgKi9cbiAgY29uc3RydWN0b3IobWVzc2FnZSwge2xvY2tOYW1lLCByZXF1ZXN0ZWRCYWNrZW5kLCBtaW5UaWVyfSkge1xuICAgIHN1cGVyKG1lc3NhZ2UpXG4gICAgdGhpcy5uYW1lID0gXCJBZHZpc29yeUxvY2tNaW5UaWVyUmVmdXNlZEVycm9yXCJcbiAgICB0aGlzLmxvY2tOYW1lID0gbG9ja05hbWVcbiAgICB0aGlzLnJlcXVlc3RlZEJhY2tlbmQgPSByZXF1ZXN0ZWRCYWNrZW5kXG4gICAgdGhpcy5taW5UaWVyID0gbWluVGllclxuICB9XG59XG5cbi8qKlxuICogVGhyb3duIHdoZW4gbm8gZW5hYmxlZCBiYWNrZW5kIHRoYXQgc2F0aXNmaWVzIHRoZSBsb2NrIG5hbWUncyBtaW5pbXVtIHRpZXJcbiAqIGlzIGF2YWlsYWJsZSAowqc5KS4gRGlzdGluY3QgZnJvbSBgQWR2aXNvcnlMb2NrVGltZW91dEVycm9yYCAoYSBiYWNrZW5kXG4gKiBzZXJ2ZWQgdGhlIHdhaXQgYnV0IHRoZSBob2xkZXIgbmV2ZXIgcmVsZWFzZWQpLlxuICovXG5leHBvcnQgY2xhc3MgQWR2aXNvcnlMb2NrQmFja2VuZFVuYXZhaWxhYmxlRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIEVycm9yIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSB7e2xvY2tOYW1lOiBzdHJpbmcsIG1pblRpZXI6IEFkdmlzb3J5TG9ja1RpZXIsIHJlYXNvbnM6IHN0cmluZ1tdfX0gYXJncyAtIFVuYXZhaWxhYmlsaXR5IGRldGFpbHMuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCB7bG9ja05hbWUsIG1pblRpZXIsIHJlYXNvbnN9KSB7XG4gICAgc3VwZXIobWVzc2FnZSlcbiAgICB0aGlzLm5hbWUgPSBcIkFkdmlzb3J5TG9ja0JhY2tlbmRVbmF2YWlsYWJsZUVycm9yXCJcbiAgICB0aGlzLmxvY2tOYW1lID0gbG9ja05hbWVcbiAgICB0aGlzLm1pblRpZXIgPSBtaW5UaWVyXG4gICAgdGhpcy5yZWFzb25zID0gcmVhc29uc1xuICB9XG59XG5cbi8qKlxuICogVGllciBzdHJlbmd0aCByYW5rcyAowqc5KTogaGlnaGVyIHJhbmsgaXMgc3Ryb25nZXIuIGBsb2NrLXNlcnZlcmAgYW5kXG4gKiBgZHJpdmVyLW5hdGl2ZWAgYXJlIGJvdGggY3Jvc3MtaG9zdCBhbmQgcmFuayBlcXVhbC5cbiAqIEB0eXBlIHtSZWNvcmQ8QWR2aXNvcnlMb2NrVGllciwgbnVtYmVyPn0gKi9cbmNvbnN0IFRJRVJfUkFOS1MgPSB7XG4gIFwiZHJpdmVyLW5hdGl2ZVwiOiAyLFxuICBmaWxlOiAxLFxuICBcImxvY2stc2VydmVyXCI6IDMsXG4gIFwicHJvY2Vzcy1sb2NhbFwiOiAwXG59XG5cbi8qKiBBbGwgdGllcnMgb3JkZXJlZCBzdHJvbmdlc3QtZmlyc3QuICovXG5jb25zdCBUSUVSU19TVFJPTkdFU1RfRklSU1QgPSAvKiogQHR5cGUge0Fkdmlzb3J5TG9ja1RpZXJbXX0gKi8gKFtcImxvY2stc2VydmVyXCIsIFwiZHJpdmVyLW5hdGl2ZVwiLCBcImZpbGVcIiwgXCJwcm9jZXNzLWxvY2FsXCJdKVxuXG4vKipcbiAqIFJ1bnMgdGllciByYW5rLlxuICogQHBhcmFtIHtBZHZpc29yeUxvY2tUaWVyfSB0aWVyIC0gVGllciB0byByYW5rLlxuICogQHJldHVybnMge251bWJlcn0gLSBTdHJlbmd0aCByYW5rIChoaWdoZXIgaXMgc3Ryb25nZXIpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWR2aXNvcnlMb2NrVGllclJhbmsodGllcikge1xuICBjb25zdCByYW5rID0gVElFUl9SQU5LU1t0aWVyXVxuXG4gIGlmIChyYW5rID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBhZHZpc29yeS1sb2NrIHRpZXIgJHtKU09OLnN0cmluZ2lmeShTdHJpbmcodGllcikpfWApXG5cbiAgcmV0dXJuIHJhbmtcbn1cblxuLyoqXG4gKiBSdW5zIHRpZXIgaXMgYXQgbGVhc3QgYXMgc3Ryb25nIGFzLlxuICogQHBhcmFtIHtBZHZpc29yeUxvY2tUaWVyfSB0aWVyIC0gQ2FuZGlkYXRlIHNlcnZpbmcgdGllci5cbiAqIEBwYXJhbSB7QWR2aXNvcnlMb2NrVGllcn0gbWluaW11bSAtIFJlcXVpcmVkIG1pbmltdW0gdGllci5cbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFdoZXRoZXIgYHRpZXJgIHNhdGlzZmllcyB0aGUgbWluaW11bS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFkdmlzb3J5TG9ja1RpZXJTYXRpc2ZpZXModGllciwgbWluaW11bSkge1xuICByZXR1cm4gYWR2aXNvcnlMb2NrVGllclJhbmsodGllcikgPj0gYWR2aXNvcnlMb2NrVGllclJhbmsobWluaW11bSlcbn1cblxuLyoqXG4gKiBSZXNvbHZlcyB0aGUgZWZmZWN0aXZlIGJhY2tlbmQgcG9saWN5IGZvciBvbmUgY29uY3JldGUgbG9jayBuYW1lOlxuICogbG9uZ2VzdC1wcmVmaXggZ2xvYiBtYXRjaCBvdmVyIHRoZSBjb25maWd1cmVkIGVudHJpZXMgKGV4YWN0IG5hbWVzIHdpbiksXG4gKiBkZWZhdWx0LWRlbnkgZm9yIHVuZGVjbGFyZWQgbmFtZXMgKGBtaW5UaWVyOiBkcml2ZXItbmF0aXZlYCxcbiAqIGBwcmVmZXJyZWRUaWVyOiBkcml2ZXItbmF0aXZlYCksIGFuZCBgYWxsb3dlZFRpZXJzYCBjbG9zZWQgdXB3YXJkIHNvIGFcbiAqIGNyb3NzLWhvc3QgbWluaW11bSBjYW4gbmV2ZXIgYmUgc2VydmVkIGJ5IGEgaG9zdC1sb2NhbCB0aWVyLlxuICogQHBhcmFtIHtzdHJpbmd9IGxvY2tOYW1lIC0gQ29uY3JldGUgbG9jayBuYW1lLlxuICogQHBhcmFtIHtBZHZpc29yeUxvY2tCYWNrZW5kUG9saWN5RW50cnlbXSB8IHVuZGVmaW5lZH0gcG9saWN5IC0gQ29uZmlndXJlZCBwb2xpY3kgZW50cmllcy5cbiAqIEByZXR1cm5zIHtSZXNvbHZlZEFkdmlzb3J5TG9ja0JhY2tlbmRQb2xpY3l9IC0gUmVzb2x2ZWQgcG9saWN5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUFkdmlzb3J5TG9ja0JhY2tlbmRQb2xpY3kobG9ja05hbWUsIHBvbGljeSkge1xuICBjb25zdCBlbnRyeSA9IG1hdGNoQWR2aXNvcnlMb2NrUG9saWN5RW50cnkobG9ja05hbWUsIHBvbGljeSlcbiAgY29uc3QgbWluVGllciA9IGVudHJ5Py5taW5UaWVyID8/IFwiZHJpdmVyLW5hdGl2ZVwiXG4gIGNvbnN0IHByZWZlcnJlZFRpZXIgPSBlbnRyeT8ucHJlZmVycmVkVGllciA/PyBcImRyaXZlci1uYXRpdmVcIlxuXG4gIC8vIMKnOTogZWxpZ2liaWxpdHkgZmlsdGVycyB0byB0aWVyIHN0cmVuZ3RoID49IG1pblRpZXIgZXZlbiB3aGVuIGEgd2Vha2VyXG4gIC8vIHRpZXIgd2FzIGRlY2xhcmVkIGluIGBhbGxvd2VkVGllcnNgIOKAlCBhIGNyb3NzLWhvc3QgbWluaW11bSBjYW4gbmV2ZXIgYmVcbiAgLy8gc2VydmVkIGJ5IGBmaWxlYCBvciBgcHJvY2Vzcy1sb2NhbGAuIEEgYHByZWZlcnJlZFRpZXJgIGJlbG93IHRoZSBtaW5pbXVtXG4gIC8vIHN0YXlzIHZpc2libGUgaGVyZSBzbyB0aGUgcnVubmVyIGNhbiByZWZ1c2UgaXQgbG91ZGx5IGJlZm9yZSBjb250YWN0aW5nXG4gIC8vIHRoZSB3ZWFrZXIgYmFja2VuZC5cbiAgY29uc3QgZGVjbGFyZWRBbGxvd2VkID0gZW50cnk/LmFsbG93ZWRUaWVyc1xuICBjb25zdCBhbGxvd2VkVGllcnMgPSBUSUVSU19TVFJPTkdFU1RfRklSU1QuZmlsdGVyKCh0aWVyKSA9PiB7XG4gICAgaWYgKCFhZHZpc29yeUxvY2tUaWVyU2F0aXNmaWVzKHRpZXIsIG1pblRpZXIpKSByZXR1cm4gZmFsc2VcblxuICAgIGlmICghQXJyYXkuaXNBcnJheShkZWNsYXJlZEFsbG93ZWQpKSByZXR1cm4gdHJ1ZVxuXG4gICAgcmV0dXJuIGRlY2xhcmVkQWxsb3dlZC5pbmNsdWRlcyh0aWVyKVxuICB9KVxuXG4gIHJldHVybiB7YWxsb3dlZFRpZXJzLCBlbnRyeTogZW50cnkgPz8gbnVsbCwgbWluVGllciwgcHJlZmVycmVkVGllcn1cbn1cblxuLyoqXG4gKiBNYXRjaGVzIG9uZSBwb2xpY3kgZW50cnkgZm9yIGEgbG9jayBuYW1lOiBleGFjdCBgbmFtZWAgbWF0Y2hlcyB3aW47XG4gKiBvdGhlcndpc2UgdGhlIGxvbmdlc3QgYCpgLXN1ZmZpeGVkIHByZWZpeCBwYXR0ZXJuIHdpbnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9ja05hbWUgLSBDb25jcmV0ZSBsb2NrIG5hbWUuXG4gKiBAcGFyYW0ge0Fkdmlzb3J5TG9ja0JhY2tlbmRQb2xpY3lFbnRyeVtdIHwgdW5kZWZpbmVkfSBwb2xpY3kgLSBDb25maWd1cmVkIHBvbGljeSBlbnRyaWVzLlxuICogQHJldHVybnMge0Fkdmlzb3J5TG9ja0JhY2tlbmRQb2xpY3lFbnRyeSB8IG51bGx9IC0gTWF0Y2hlZCBlbnRyeSBvciBudWxsLlxuICovXG5mdW5jdGlvbiBtYXRjaEFkdmlzb3J5TG9ja1BvbGljeUVudHJ5KGxvY2tOYW1lLCBwb2xpY3kpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHBvbGljeSkpIHJldHVybiBudWxsXG5cbiAgbGV0IGJlc3RQcmVmaXhNYXRjaCA9IG51bGxcbiAgbGV0IGJlc3RQcmVmaXhMZW5ndGggPSAtMVxuXG4gIGZvciAoY29uc3QgZW50cnkgb2YgcG9saWN5KSB7XG4gICAgaWYgKHR5cGVvZiBlbnRyeT8ubmFtZSAhPT0gXCJzdHJpbmdcIikgY29udGludWVcblxuICAgIGlmIChlbnRyeS5uYW1lID09PSBsb2NrTmFtZSkgcmV0dXJuIGVudHJ5XG5cbiAgICBpZiAoZW50cnkubmFtZS5lbmRzV2l0aChcIipcIikpIHtcbiAgICAgIGNvbnN0IHByZWZpeCA9IGVudHJ5Lm5hbWUuc2xpY2UoMCwgLTEpXG5cbiAgICAgIGlmIChsb2NrTmFtZS5zdGFydHNXaXRoKHByZWZpeCkgJiYgcHJlZml4Lmxlbmd0aCA+IGJlc3RQcmVmaXhMZW5ndGgpIHtcbiAgICAgICAgYmVzdFByZWZpeE1hdGNoID0gZW50cnlcbiAgICAgICAgYmVzdFByZWZpeExlbmd0aCA9IHByZWZpeC5sZW5ndGhcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gYmVzdFByZWZpeE1hdGNoXG59XG5cbi8qKlxuICogUmVmdXNlcyBhIGRvd25ncmFkZSBiZWxvdyB0aGUgbG9jayBuYW1lJ3MgbWluaW11bSB0aWVyIGJlZm9yZSBhbnkgY29udGFjdFxuICogd2l0aCB0aGUgd2Vha2VyIGJhY2tlbmQgKMKnOSksIHJlcG9ydGluZyB0aGUgcmVmdXNhbCBvbiB0aGUgZnJhbWV3b3JrLWVycm9yXG4gKiBjaGFubmVsIHNvIGEgc2lsZW50IGRvd25ncmFkZSBpcyBpbXBvc3NpYmxlIHRvIGhpZGUuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFJlZnVzYWwgYXJncy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uIG93bmluZyB0aGUgZXJyb3IgY2hhbm5lbC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmxvY2tOYW1lIC0gTG9jayBuYW1lLlxuICogQHBhcmFtIHtBZHZpc29yeUxvY2tUaWVyfSBhcmdzLnJlcXVlc3RlZEJhY2tlbmQgLSBUaWVyIHRoZSBhY3F1aXNpdGlvbiB3b3VsZCBmYWxsIHRvLlxuICogQHBhcmFtIHtBZHZpc29yeUxvY2tUaWVyfSBhcmdzLm1pblRpZXIgLSBEZWNsYXJlZCBtaW5pbXVtIHRpZXIuXG4gKiBAcmV0dXJucyB7bmV2ZXJ9IC0gQWx3YXlzIHRocm93cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZnVzZUFkdmlzb3J5TG9ja1RpZXJCZWxvd01pbmltdW0oe2NvbmZpZ3VyYXRpb24sIGxvY2tOYW1lLCByZXF1ZXN0ZWRCYWNrZW5kLCBtaW5UaWVyfSkge1xuICBjb25zdCBlcnJvciA9IG5ldyBBZHZpc29yeUxvY2tNaW5UaWVyUmVmdXNlZEVycm9yKFxuICAgIGBBZHZpc29yeSBsb2NrICR7SlNPTi5zdHJpbmdpZnkobG9ja05hbWUpfSByZXF1aXJlcyBtaW5pbXVtIHRpZXIgJHtKU09OLnN0cmluZ2lmeShtaW5UaWVyKX07IHRoZSAke0pTT04uc3RyaW5naWZ5KHJlcXVlc3RlZEJhY2tlbmQpfSB0aWVyIGlzIHJlZnVzZWQuIEVuYWJsZSBhIGNyb3NzLWhvc3QgYmFja2VuZCBvciBkZWNsYXJlIG1pblRpZXI6IFwiZmlsZVwiIGZvciB0aGlzIGxvY2sgbmFtZSAoc2luZ2xlLWhvc3QgZGVwbG95bWVudHMgb25seSkuYCxcbiAgICB7bG9ja05hbWUsIG1pblRpZXIsIHJlcXVlc3RlZEJhY2tlbmR9XG4gIClcblxuICBjb25maWd1cmF0aW9uLmdldEVycm9yRXZlbnRzKCkuZW1pdChcImZyYW1ld29yay1lcnJvclwiLCB7XG4gICAgY29udGV4dDogXCJhZHZpc29yeS1sb2NrLW1pbi10aWVyLXJlZnVzZWRcIixcbiAgICBlcnJvcixcbiAgICBsb2NrTmFtZSxcbiAgICBtaW5UaWVyLFxuICAgIHJlcXVlc3RlZEJhY2tlbmRcbiAgfSlcbiAgY29uZmlndXJhdGlvbi5nZXRFcnJvckV2ZW50cygpLmVtaXQoXCJhbGwtZXJyb3JcIiwge1xuICAgIGNvbnRleHQ6IFwiYWR2aXNvcnktbG9jay1taW4tdGllci1yZWZ1c2VkXCIsXG4gICAgZXJyb3IsXG4gICAgZXJyb3JUeXBlOiBcImZyYW1ld29yay1lcnJvclwiLFxuICAgIGxvY2tOYW1lLFxuICAgIG1pblRpZXIsXG4gICAgcmVxdWVzdGVkQmFja2VuZFxuICB9KVxuXG4gIHRocm93IGVycm9yXG59XG4iXX0=
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
export type AdvisoryLockFileOwner = {
|
|
2
|
+
/**
|
|
3
|
+
* - PID of the holding process.
|
|
4
|
+
*/
|
|
5
|
+
pid: number;
|
|
6
|
+
/**
|
|
7
|
+
* - Host of the holding process.
|
|
8
|
+
*/
|
|
9
|
+
hostname: string;
|
|
10
|
+
/**
|
|
11
|
+
* - Unique id of the acquiring backend instance.
|
|
12
|
+
*/
|
|
13
|
+
holderId: string;
|
|
14
|
+
/**
|
|
15
|
+
* - ISO timestamp of acquisition.
|
|
16
|
+
*/
|
|
17
|
+
acquiredAt: string;
|
|
18
|
+
/**
|
|
19
|
+
* - ISO timestamp when the current lease expires without renewal.
|
|
20
|
+
*/
|
|
21
|
+
leaseExpiresAt: string;
|
|
22
|
+
/**
|
|
23
|
+
* - Extra owner field: HTTP host (server lock only).
|
|
24
|
+
*/
|
|
25
|
+
host?: string;
|
|
26
|
+
/**
|
|
27
|
+
* - Extra owner field: HTTP port (server lock only).
|
|
28
|
+
*/
|
|
29
|
+
port?: number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Owner metadata written inside one file-lock directory.
|
|
33
|
+
* @typedef {object} AdvisoryLockFileOwner
|
|
34
|
+
* @property {number} pid - PID of the holding process.
|
|
35
|
+
* @property {string} hostname - Host of the holding process.
|
|
36
|
+
* @property {string} holderId - Unique id of the acquiring backend instance.
|
|
37
|
+
* @property {string} acquiredAt - ISO timestamp of acquisition.
|
|
38
|
+
* @property {string} leaseExpiresAt - ISO timestamp when the current lease expires without renewal.
|
|
39
|
+
* @property {string} [host] - Extra owner field: HTTP host (server lock only).
|
|
40
|
+
* @property {number} [port] - Extra owner field: HTTP port (server lock only).
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Directory-based advisory-lock backend for the STC-210 `file` tier
|
|
44
|
+
* (`docs/advisory-lock-backends.md` tier (d)). This generalizes the pattern
|
|
45
|
+
* already used by `src/http-server/server-lock.js` and the Node SQLite
|
|
46
|
+
* driver's filesystem layer into one reusable backend behind the shared
|
|
47
|
+
* advisory-lock seam:
|
|
48
|
+
*
|
|
49
|
+
* - Atomic publication: a lock is claimed by `fs.mkdtemp` + `fs.rename` onto
|
|
50
|
+
* the stable lock path, so a losing candidate never observes or deletes a
|
|
51
|
+
* half-written owner record.
|
|
52
|
+
* - Lease + renewal: each hold carries a `leaseMs` lease renewed on
|
|
53
|
+
* `renewIntervalMs` while held, so a holder that dies without releasing
|
|
54
|
+
* (or whose PID was recycled) is reclaimable once the lease expires.
|
|
55
|
+
* - Staleness: a lock directory is stale when its owner metadata is
|
|
56
|
+
* unreadable, its lease expired, or its owner is a dead local process
|
|
57
|
+
* (`kill(pid, 0)` → `ESRCH`). Cross-host owners are only reclaimable via
|
|
58
|
+
* lease expiry because PID liveness cannot be probed remotely.
|
|
59
|
+
*
|
|
60
|
+
* This tier provides no fencing tokens (design §8: a file lock has no
|
|
61
|
+
* monotonic authority a partitioned holder can be checked against), so
|
|
62
|
+
* acquisitions report `fencingSupported: false` instead of pretending.
|
|
63
|
+
*/
|
|
64
|
+
export default class AdvisoryLockFileBackend {
|
|
65
|
+
directory: string;
|
|
66
|
+
extraOwnerFields: Record<string, string | number>;
|
|
67
|
+
leaseMs: number;
|
|
68
|
+
renewIntervalMs: number;
|
|
69
|
+
pathStyle: "hashed" | "plain";
|
|
70
|
+
pollIntervalMs: number;
|
|
71
|
+
holderId: string;
|
|
72
|
+
/** @type {Map<string, {timer: ReturnType<typeof setInterval>}>} */
|
|
73
|
+
holdsByName: Map<string, {
|
|
74
|
+
timer: ReturnType<typeof setInterval>;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Creates one file-lock backend.
|
|
78
|
+
* @param {object} args - Backend options.
|
|
79
|
+
* @param {string} args.directory - Directory that holds the lock directories.
|
|
80
|
+
* @param {Record<string, string | number>} [args.extraOwnerFields] - Extra fields merged into every owner metadata record (e.g. the HTTP server lock's host/port).
|
|
81
|
+
* @param {number} [args.leaseMs] - Lease duration for one hold; expired leases make a lock stale. Defaults to 30000.
|
|
82
|
+
* @param {number} [args.renewIntervalMs] - Renewal cadence while holding; must stay below `leaseMs`. Defaults to 10000.
|
|
83
|
+
* @param {"hashed" | "plain"} [args.pathStyle] - `hashed` derives `<safeName>-<hash>.lock` names (advisory-lock tier); `plain` uses `<name>.lock` (HTTP server lock). Defaults to `hashed`.
|
|
84
|
+
* @param {number} [args.pollIntervalMs] - Wait between acquisition retries. Defaults to 50.
|
|
85
|
+
*/
|
|
86
|
+
constructor({ directory, extraOwnerFields, leaseMs, renewIntervalMs, pathStyle, pollIntervalMs }: {
|
|
87
|
+
directory: string;
|
|
88
|
+
extraOwnerFields?: Record<string, string | number>;
|
|
89
|
+
leaseMs?: number;
|
|
90
|
+
renewIntervalMs?: number;
|
|
91
|
+
pathStyle?: "hashed" | "plain";
|
|
92
|
+
pollIntervalMs?: number;
|
|
93
|
+
});
|
|
94
|
+
/**
|
|
95
|
+
* Resolves the stable lock directory path for one lock name.
|
|
96
|
+
* @param {string} name - Lock name.
|
|
97
|
+
* @returns {string} - Filesystem path for the lock directory.
|
|
98
|
+
*/
|
|
99
|
+
lockPathFor(name: string): string;
|
|
100
|
+
/**
|
|
101
|
+
* Blocks until the named lock is acquired or `timeoutMs` elapses.
|
|
102
|
+
* @param {string} name - Lock name.
|
|
103
|
+
* @param {{timeoutMs?: number | null}} [args] - Timeout args; `null`, `undefined`, or negative waits indefinitely.
|
|
104
|
+
* @returns {Promise<boolean>} - True when acquired, false when the timeout elapsed.
|
|
105
|
+
*/
|
|
106
|
+
acquire(name: string, { timeoutMs }?: {
|
|
107
|
+
timeoutMs?: number | null;
|
|
108
|
+
}): Promise<boolean>;
|
|
109
|
+
/**
|
|
110
|
+
* Attempts to acquire the named lock without waiting, reclaiming a stale
|
|
111
|
+
* lock directory when one is found.
|
|
112
|
+
* @param {string} name - Lock name.
|
|
113
|
+
* @returns {Promise<boolean>} - True when this backend became the lock owner.
|
|
114
|
+
*/
|
|
115
|
+
tryAcquire(name: string): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Releases the lock only when this backend instance owns it, mirroring the
|
|
118
|
+
* "you can only release locks you own" contract of the database tiers.
|
|
119
|
+
* @param {string} name - Lock name.
|
|
120
|
+
* @returns {Promise<boolean>} - True when the held lock was released.
|
|
121
|
+
*/
|
|
122
|
+
release(name: string): Promise<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* Runs is held.
|
|
125
|
+
* @param {string} name - Lock name.
|
|
126
|
+
* @returns {Promise<boolean>} - Whether the lock is currently held by a live, unexpired owner.
|
|
127
|
+
*/
|
|
128
|
+
isHeld(name: string): Promise<boolean>;
|
|
129
|
+
/**
|
|
130
|
+
* Reads the current owner metadata for diagnostics.
|
|
131
|
+
* @param {string} name - Lock name.
|
|
132
|
+
* @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when a lock directory exists.
|
|
133
|
+
*/
|
|
134
|
+
holderInfo(name: string): Promise<AdvisoryLockFileOwner | null>;
|
|
135
|
+
/**
|
|
136
|
+
* Releases every lock this backend instance currently holds (shutdown path).
|
|
137
|
+
* @returns {Promise<void>} - Resolves after best-effort release of all holds.
|
|
138
|
+
*/
|
|
139
|
+
releaseAllHeld(): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Ensures the parent lock directory exists.
|
|
142
|
+
* @returns {Promise<void>} - Resolves after the directory exists.
|
|
143
|
+
*/
|
|
144
|
+
ensureDirectory(): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* Publishes a fully initialized lock directory with one atomic rename so
|
|
147
|
+
* concurrent candidates cannot observe a half-written owner record.
|
|
148
|
+
* @param {string} lockPath - Stable lock directory path.
|
|
149
|
+
* @returns {Promise<boolean>} - Whether this candidate became the lock owner.
|
|
150
|
+
*/
|
|
151
|
+
publishLockDirectory(lockPath: string): Promise<boolean>;
|
|
152
|
+
/**
|
|
153
|
+
* Starts lease renewal for a freshly acquired hold.
|
|
154
|
+
* @param {string} name - Lock name.
|
|
155
|
+
* @returns {true} - Always true; the hold is now tracked.
|
|
156
|
+
*/
|
|
157
|
+
startHold(name: string): true;
|
|
158
|
+
/**
|
|
159
|
+
* Extends this instance's lease on one held lock; stops renewing when the
|
|
160
|
+
* directory is no longer ours (the lock was reclaimed).
|
|
161
|
+
* @param {string} name - Lock name.
|
|
162
|
+
* @returns {Promise<void>} - Resolves after the renewal attempt.
|
|
163
|
+
*/
|
|
164
|
+
renewHold(name: string): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Clears the renewal timer for one hold.
|
|
167
|
+
* @param {string} name - Lock name.
|
|
168
|
+
* @returns {void}
|
|
169
|
+
*/
|
|
170
|
+
clearHold(name: string): void;
|
|
171
|
+
/**
|
|
172
|
+
* Writes owner + lease metadata into a lock directory.
|
|
173
|
+
* @param {string} lockDirPath - Lock directory to write metadata into.
|
|
174
|
+
* @returns {Promise<void>} - Resolves after metadata is written.
|
|
175
|
+
*/
|
|
176
|
+
writeOwner(lockDirPath: string): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Reads owner metadata from a lock directory.
|
|
179
|
+
* @param {string} lockPath - Lock directory path.
|
|
180
|
+
* @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when readable.
|
|
181
|
+
*/
|
|
182
|
+
readOwner(lockPath: string): Promise<AdvisoryLockFileOwner | null>;
|
|
183
|
+
/**
|
|
184
|
+
* A lock directory is stale when its metadata is unreadable, its lease has
|
|
185
|
+
* expired, or its owner is a dead process on this host. Cross-host owners
|
|
186
|
+
* are only reclaimable via lease expiry — PID probing is unreliable beyond
|
|
187
|
+
* one host, which is exactly why this tier is the opt-in single-host last
|
|
188
|
+
* resort (design §4/§8).
|
|
189
|
+
* @param {string} lockPath - Lock directory path.
|
|
190
|
+
* @returns {Promise<boolean>} - Whether the lock can be reclaimed.
|
|
191
|
+
*/
|
|
192
|
+
isStale(lockPath: string): Promise<boolean>;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=advisory-lock-file-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advisory-lock-file-backend.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-file-backend.js"],"names":[],"mappings":"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"}
|