@qitqode/qitqore 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +165 -0
- package/dist/decision-policy.d.ts +132 -0
- package/dist/decision-policy.d.ts.map +1 -0
- package/dist/decision-policy.js +308 -0
- package/dist/decision-policy.js.map +1 -0
- package/dist/device-authorization.d.ts +67 -0
- package/dist/device-authorization.d.ts.map +1 -0
- package/dist/device-authorization.js +122 -0
- package/dist/device-authorization.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +108 -17
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/recovery-capabilities.d.ts +26 -0
- package/dist/recovery-capabilities.d.ts.map +1 -0
- package/dist/recovery-capabilities.js +113 -0
- package/dist/recovery-capabilities.js.map +1 -0
- package/dist/recovery-directive.d.ts +20 -0
- package/dist/recovery-directive.d.ts.map +1 -0
- package/dist/recovery-directive.js +116 -0
- package/dist/recovery-directive.js.map +1 -0
- package/dist/recovery-lease.d.ts +80 -0
- package/dist/recovery-lease.d.ts.map +1 -0
- package/dist/recovery-lease.js +257 -0
- package/dist/recovery-lease.js.map +1 -0
- package/dist/recovery-status.d.ts +22 -0
- package/dist/recovery-status.d.ts.map +1 -0
- package/dist/recovery-status.js +113 -0
- package/dist/recovery-status.js.map +1 -0
- package/dist/recovery.d.ts +13 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +94 -55
- package/dist/recovery.js.map +1 -1
- package/dist/redaction.d.ts +64 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +154 -0
- package/dist/redaction.js.map +1 -0
- package/dist/route-contract.d.ts +36 -0
- package/dist/route-contract.d.ts.map +1 -0
- package/dist/route-contract.js +89 -0
- package/dist/route-contract.js.map +1 -0
- package/dist/sse.d.ts +4 -0
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +16 -1
- package/dist/sse.js.map +1 -1
- package/dist/stream-payload.d.ts +40 -0
- package/dist/stream-payload.d.ts.map +1 -0
- package/dist/stream-payload.js +96 -0
- package/dist/stream-payload.js.map +1 -0
- package/dist/transport.d.ts +10 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +28 -0
- package/dist/transport.js.map +1 -1
- package/package.json +12 -2
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const MODES = new Set(["buffered", "streaming", "async_job", "utility"]);
|
|
2
|
+
const RETRIES = new Set(["pre_execution_only", "safe_observation", "unsupported"]);
|
|
3
|
+
const REPLAYS = new Set(["retained_result", "unsupported"]);
|
|
4
|
+
const RESUMES = new Set(["supported", "unsupported"]);
|
|
5
|
+
const RECONCILIATIONS = new Set([
|
|
6
|
+
"recovery_status",
|
|
7
|
+
"billing_status_only",
|
|
8
|
+
"job_status",
|
|
9
|
+
"unsupported",
|
|
10
|
+
]);
|
|
11
|
+
const MANIFEST_FIELDS = new Set(["success", "contractVersion", "capabilities"]);
|
|
12
|
+
const CAPABILITY_FIELDS = new Set([
|
|
13
|
+
"contractVersion",
|
|
14
|
+
"routeID",
|
|
15
|
+
"mode",
|
|
16
|
+
"retry",
|
|
17
|
+
"replay",
|
|
18
|
+
"resume",
|
|
19
|
+
"reconciliation",
|
|
20
|
+
"requiresIdempotencyKey",
|
|
21
|
+
"retentionMs",
|
|
22
|
+
"maxBackendAdditionalWork",
|
|
23
|
+
]);
|
|
24
|
+
const MAX_CAPABILITIES = 512;
|
|
25
|
+
function isRecord(value) {
|
|
26
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
27
|
+
}
|
|
28
|
+
function boundedString(value, field, maxLength) {
|
|
29
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
|
|
30
|
+
throw new TypeError(`Qortex recovery capabilities have an invalid ${field}`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
/** Parse one route capability. Unrecognized fields are rejected rather than forwarded. */
|
|
35
|
+
export function parseRecoveryCapability(value) {
|
|
36
|
+
if (!isRecord(value))
|
|
37
|
+
throw new TypeError("Qortex recovery capability must be an object");
|
|
38
|
+
for (const key of Object.keys(value)) {
|
|
39
|
+
if (!CAPABILITY_FIELDS.has(key)) {
|
|
40
|
+
throw new TypeError("Qortex recovery capability contains an unsupported field");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (value.contractVersion !== 1) {
|
|
44
|
+
throw new TypeError("Qortex recovery capability uses an unsupported contract version");
|
|
45
|
+
}
|
|
46
|
+
if (typeof value.mode !== "string" || !MODES.has(value.mode)) {
|
|
47
|
+
throw new TypeError("Qortex recovery capability has an invalid mode");
|
|
48
|
+
}
|
|
49
|
+
if (typeof value.retry !== "string" || !RETRIES.has(value.retry)) {
|
|
50
|
+
throw new TypeError("Qortex recovery capability has an invalid retry policy");
|
|
51
|
+
}
|
|
52
|
+
if (typeof value.replay !== "string" || !REPLAYS.has(value.replay)) {
|
|
53
|
+
throw new TypeError("Qortex recovery capability has an invalid replay policy");
|
|
54
|
+
}
|
|
55
|
+
if (typeof value.resume !== "string" || !RESUMES.has(value.resume)) {
|
|
56
|
+
throw new TypeError("Qortex recovery capability has an invalid resume policy");
|
|
57
|
+
}
|
|
58
|
+
if (typeof value.reconciliation !== "string" || !RECONCILIATIONS.has(value.reconciliation)) {
|
|
59
|
+
throw new TypeError("Qortex recovery capability has an invalid reconciliation policy");
|
|
60
|
+
}
|
|
61
|
+
if (typeof value.requiresIdempotencyKey !== "boolean") {
|
|
62
|
+
throw new TypeError("Qortex recovery capability has an invalid idempotency requirement");
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isSafeInteger(value.maxBackendAdditionalWork) ||
|
|
65
|
+
value.maxBackendAdditionalWork < 0) {
|
|
66
|
+
throw new TypeError("Qortex recovery capability has an invalid additional-work limit");
|
|
67
|
+
}
|
|
68
|
+
if (value.retentionMs !== undefined &&
|
|
69
|
+
(!Number.isSafeInteger(value.retentionMs) || value.retentionMs <= 0)) {
|
|
70
|
+
throw new TypeError("Qortex recovery capability has an invalid retention period");
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
contractVersion: 1,
|
|
74
|
+
routeID: boundedString(value.routeID, "routeID", 256),
|
|
75
|
+
mode: value.mode,
|
|
76
|
+
retry: value.retry,
|
|
77
|
+
replay: value.replay,
|
|
78
|
+
resume: value.resume,
|
|
79
|
+
reconciliation: value.reconciliation,
|
|
80
|
+
requiresIdempotencyKey: value.requiresIdempotencyKey,
|
|
81
|
+
...(value.retentionMs === undefined ? {} : { retentionMs: value.retentionMs }),
|
|
82
|
+
maxBackendAdditionalWork: value.maxBackendAdditionalWork,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Parse only bounded route facts; never pass through unrecognized server metadata. */
|
|
86
|
+
export function parseRecoveryCapabilities(value) {
|
|
87
|
+
if (!isRecord(value))
|
|
88
|
+
throw new TypeError("Qortex recovery capabilities must be an object");
|
|
89
|
+
let candidate = value;
|
|
90
|
+
if (value.success === true && Object.hasOwn(value, "data"))
|
|
91
|
+
candidate = value.data;
|
|
92
|
+
if (!isRecord(candidate))
|
|
93
|
+
throw new TypeError("Qortex recovery capabilities data must be an object");
|
|
94
|
+
for (const key of Object.keys(candidate)) {
|
|
95
|
+
if (!MANIFEST_FIELDS.has(key)) {
|
|
96
|
+
throw new TypeError("Qortex recovery capabilities contain an unsupported field");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (candidate.success !== undefined && candidate.success !== true) {
|
|
100
|
+
throw new TypeError("Qortex recovery capabilities have an invalid success marker");
|
|
101
|
+
}
|
|
102
|
+
if (candidate.contractVersion !== 1) {
|
|
103
|
+
throw new TypeError("Qortex recovery capabilities use an unsupported contract version");
|
|
104
|
+
}
|
|
105
|
+
if (!Array.isArray(candidate.capabilities) || candidate.capabilities.length > MAX_CAPABILITIES) {
|
|
106
|
+
throw new TypeError("Qortex recovery capabilities have an invalid capability list");
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
contractVersion: 1,
|
|
110
|
+
capabilities: candidate.capabilities.map(parseRecoveryCapability),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=recovery-capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-capabilities.js","sourceRoot":"","sources":["../src/recovery-capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { QortexExecutionState } from "./recovery-status.js";
|
|
2
|
+
export type QortexRecoveryFailureLayer = "client" | "qortex_transport" | "qortex_auth" | "qortex_harness" | "omniquery_inference" | "tool" | "verification" | "capability";
|
|
3
|
+
export type QortexRecoveryFailureCategory = "backend_unavailable" | "authentication_rejected" | "backend_harness_failed" | "inference_failed" | "tool_failed" | "tool_running" | "verification_failed" | "unsupported_capability" | "rate_limited" | "operation_budget_exhausted" | "operation_deadline_expired" | "effect_outcome_unknown" | "cancelled" | "invalid_request" | "internal_failure";
|
|
4
|
+
export type QortexRecommendedRecoveryAction = "retry_same_work" | "replay_retained_result" | "continue_partial" | "change_approach" | "reconcile" | "wait" | "reauthenticate" | "stop";
|
|
5
|
+
export interface QortexRecoveryDirective {
|
|
6
|
+
contractVersion: 1;
|
|
7
|
+
policyVersion: string;
|
|
8
|
+
category: QortexRecoveryFailureCategory;
|
|
9
|
+
layer: QortexRecoveryFailureLayer;
|
|
10
|
+
stage: string;
|
|
11
|
+
executionState: QortexExecutionState | "accepted" | "cancelled";
|
|
12
|
+
recommendedAction: QortexRecommendedRecoveryAction;
|
|
13
|
+
retryable: boolean;
|
|
14
|
+
reasonCode: string;
|
|
15
|
+
requestID?: string;
|
|
16
|
+
retryAfterMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Parse the public directive without retaining unrecognized provider or server fields. */
|
|
19
|
+
export declare function parseRecoveryDirective(value: unknown): QortexRecoveryDirective;
|
|
20
|
+
//# sourceMappingURL=recovery-directive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-directive.d.ts","sourceRoot":"","sources":["../src/recovery-directive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,MAAM,0BAA0B,GAClC,QAAQ,GACR,kBAAkB,GAClB,aAAa,GACb,gBAAgB,GAChB,qBAAqB,GACrB,MAAM,GACN,cAAc,GACd,YAAY,CAAC;AAEjB,MAAM,MAAM,6BAA6B,GACrC,qBAAqB,GACrB,yBAAyB,GACzB,wBAAwB,GACxB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,qBAAqB,GACrB,wBAAwB,GACxB,cAAc,GACd,4BAA4B,GAC5B,4BAA4B,GAC5B,wBAAwB,GACxB,WAAW,GACX,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB,MAAM,MAAM,+BAA+B,GACvC,iBAAiB,GACjB,wBAAwB,GACxB,kBAAkB,GAClB,iBAAiB,GACjB,WAAW,GACX,MAAM,GACN,gBAAgB,GAChB,MAAM,CAAC;AAEX,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,CAAC,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,6BAA6B,CAAC;IACxC,KAAK,EAAE,0BAA0B,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,oBAAoB,GAAG,UAAU,GAAG,WAAW,CAAC;IAChE,iBAAiB,EAAE,+BAA+B,CAAC;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA8DD,2FAA2F;AAC3F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAyD9E"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const CATEGORIES = new Set([
|
|
2
|
+
"backend_unavailable",
|
|
3
|
+
"authentication_rejected",
|
|
4
|
+
"backend_harness_failed",
|
|
5
|
+
"inference_failed",
|
|
6
|
+
"tool_failed",
|
|
7
|
+
"tool_running",
|
|
8
|
+
"verification_failed",
|
|
9
|
+
"unsupported_capability",
|
|
10
|
+
"rate_limited",
|
|
11
|
+
"operation_budget_exhausted",
|
|
12
|
+
"operation_deadline_expired",
|
|
13
|
+
"effect_outcome_unknown",
|
|
14
|
+
"cancelled",
|
|
15
|
+
"invalid_request",
|
|
16
|
+
"internal_failure",
|
|
17
|
+
]);
|
|
18
|
+
const LAYERS = new Set([
|
|
19
|
+
"client",
|
|
20
|
+
"qortex_transport",
|
|
21
|
+
"qortex_auth",
|
|
22
|
+
"qortex_harness",
|
|
23
|
+
"omniquery_inference",
|
|
24
|
+
"tool",
|
|
25
|
+
"verification",
|
|
26
|
+
"capability",
|
|
27
|
+
]);
|
|
28
|
+
const ACTIONS = new Set([
|
|
29
|
+
"retry_same_work",
|
|
30
|
+
"replay_retained_result",
|
|
31
|
+
"continue_partial",
|
|
32
|
+
"change_approach",
|
|
33
|
+
"reconcile",
|
|
34
|
+
"wait",
|
|
35
|
+
"reauthenticate",
|
|
36
|
+
"stop",
|
|
37
|
+
]);
|
|
38
|
+
const EXECUTION_STATES = new Set(["not_started", "accepted", "running", "succeeded", "failed", "unknown", "cancelled"]);
|
|
39
|
+
const FIELDS = new Set([
|
|
40
|
+
"contractVersion",
|
|
41
|
+
"policyVersion",
|
|
42
|
+
"category",
|
|
43
|
+
"layer",
|
|
44
|
+
"stage",
|
|
45
|
+
"executionState",
|
|
46
|
+
"recommendedAction",
|
|
47
|
+
"retryable",
|
|
48
|
+
"reasonCode",
|
|
49
|
+
"requestID",
|
|
50
|
+
"retryAfterMs",
|
|
51
|
+
]);
|
|
52
|
+
function isRecord(value) {
|
|
53
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
function matches(value, pattern) {
|
|
56
|
+
return typeof value === "string" && pattern.test(value);
|
|
57
|
+
}
|
|
58
|
+
/** Parse the public directive without retaining unrecognized provider or server fields. */
|
|
59
|
+
export function parseRecoveryDirective(value) {
|
|
60
|
+
if (!isRecord(value))
|
|
61
|
+
throw new TypeError("Qortex recovery directive must be an object");
|
|
62
|
+
for (const key of Object.keys(value)) {
|
|
63
|
+
if (!FIELDS.has(key))
|
|
64
|
+
throw new TypeError("Qortex recovery directive contains an unsupported field");
|
|
65
|
+
}
|
|
66
|
+
if (value.contractVersion !== 1) {
|
|
67
|
+
throw new TypeError("Qortex recovery directive uses an unsupported contract version");
|
|
68
|
+
}
|
|
69
|
+
if (!matches(value.policyVersion, /^[A-Za-z0-9_.:-]{1,256}$/)) {
|
|
70
|
+
throw new TypeError("Qortex recovery directive has an invalid policyVersion");
|
|
71
|
+
}
|
|
72
|
+
if (typeof value.category !== "string" || !CATEGORIES.has(value.category)) {
|
|
73
|
+
throw new TypeError("Qortex recovery directive has an invalid category");
|
|
74
|
+
}
|
|
75
|
+
if (typeof value.layer !== "string" || !LAYERS.has(value.layer)) {
|
|
76
|
+
throw new TypeError("Qortex recovery directive has an invalid layer");
|
|
77
|
+
}
|
|
78
|
+
if (!matches(value.stage, /^[A-Za-z0-9_.:-]{1,128}$/)) {
|
|
79
|
+
throw new TypeError("Qortex recovery directive has an invalid stage");
|
|
80
|
+
}
|
|
81
|
+
if (typeof value.executionState !== "string" || !EXECUTION_STATES.has(value.executionState)) {
|
|
82
|
+
throw new TypeError("Qortex recovery directive has an invalid executionState");
|
|
83
|
+
}
|
|
84
|
+
if (typeof value.recommendedAction !== "string" || !ACTIONS.has(value.recommendedAction)) {
|
|
85
|
+
throw new TypeError("Qortex recovery directive has an invalid recommendedAction");
|
|
86
|
+
}
|
|
87
|
+
if (typeof value.retryable !== "boolean") {
|
|
88
|
+
throw new TypeError("Qortex recovery directive has an invalid retryable flag");
|
|
89
|
+
}
|
|
90
|
+
if (!matches(value.reasonCode, /^[a-z0-9_:-]{1,256}$/)) {
|
|
91
|
+
throw new TypeError("Qortex recovery directive has an invalid reasonCode");
|
|
92
|
+
}
|
|
93
|
+
if (value.requestID !== undefined && !matches(value.requestID, /^[A-Za-z0-9_.:/-]{1,256}$/)) {
|
|
94
|
+
throw new TypeError("Qortex recovery directive has an invalid requestID");
|
|
95
|
+
}
|
|
96
|
+
if (value.retryAfterMs !== undefined &&
|
|
97
|
+
(!Number.isSafeInteger(value.retryAfterMs) ||
|
|
98
|
+
value.retryAfterMs < 0 ||
|
|
99
|
+
value.retryAfterMs > 86_400_000)) {
|
|
100
|
+
throw new TypeError("Qortex recovery directive has an invalid retryAfterMs");
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
contractVersion: 1,
|
|
104
|
+
policyVersion: value.policyVersion,
|
|
105
|
+
category: value.category,
|
|
106
|
+
layer: value.layer,
|
|
107
|
+
stage: value.stage,
|
|
108
|
+
executionState: value.executionState,
|
|
109
|
+
recommendedAction: value.recommendedAction,
|
|
110
|
+
retryable: value.retryable,
|
|
111
|
+
reasonCode: value.reasonCode,
|
|
112
|
+
...(value.requestID === undefined ? {} : { requestID: value.requestID }),
|
|
113
|
+
...(value.retryAfterMs === undefined ? {} : { retryAfterMs: value.retryAfterMs }),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=recovery-directive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-directive.js","sourceRoot":"","sources":["../src/recovery-directive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qortex's recovery lease wire contract: the control envelope a host sends to
|
|
3
|
+
* bound additional work, and the usage projection Qortex returns for it.
|
|
4
|
+
* QitQore parses and encodes these values only. Hosts allocate token budgets,
|
|
5
|
+
* persist leases, authorize replay, and settle outcomes.
|
|
6
|
+
*/
|
|
7
|
+
/** Request header that carries a base64url-encoded control envelope to Qortex. */
|
|
8
|
+
export declare const QORTEX_RECOVERY_CONTROL_HEADER = "x-qitqode-recovery-control";
|
|
9
|
+
/** Maximum additional-work tokens in one lease, matching Qortex's public limit. */
|
|
10
|
+
export declare const MAX_RECOVERY_ADDITIONAL_WORK = 12;
|
|
11
|
+
/** Longest root-operation window Qortex will honor for one dispatch. */
|
|
12
|
+
export declare const MAX_RECOVERY_ROOT_REMAINING_MS: number;
|
|
13
|
+
export type QortexRecoveryAdditionalWorkAction = "retry_same_work" | "changed_approach" | "continuation" | "compaction" | "worker" | "reconciliation";
|
|
14
|
+
export type QortexRecoveryAction = QortexRecoveryAdditionalWorkAction | "initial_dispatch";
|
|
15
|
+
export interface QortexRecoveryConsumedWork {
|
|
16
|
+
tokenID: string;
|
|
17
|
+
action: QortexRecoveryAdditionalWorkAction;
|
|
18
|
+
stage: string;
|
|
19
|
+
}
|
|
20
|
+
/** Qortex's report of which reserved tokens a request consumed and which it left unused. */
|
|
21
|
+
export interface QortexRecoveryLeaseUsage {
|
|
22
|
+
contractVersion: 1;
|
|
23
|
+
leaseID: string;
|
|
24
|
+
publicOperationID: string;
|
|
25
|
+
operationGeneration: number;
|
|
26
|
+
workID: string;
|
|
27
|
+
attemptID: string;
|
|
28
|
+
requestID: string;
|
|
29
|
+
routeID: string;
|
|
30
|
+
consumed: QortexRecoveryConsumedWork[];
|
|
31
|
+
unusedTokenIDs: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface QortexRecoveryControlOperation {
|
|
34
|
+
contractVersion: 1;
|
|
35
|
+
publicOperationID: string;
|
|
36
|
+
operationGeneration: number;
|
|
37
|
+
workID: string;
|
|
38
|
+
attemptID: string;
|
|
39
|
+
parentWorkID?: string;
|
|
40
|
+
action: QortexRecoveryAction;
|
|
41
|
+
rootDeadlineAt: number;
|
|
42
|
+
rootRemainingMsAtDispatch: number;
|
|
43
|
+
claimID?: string;
|
|
44
|
+
leaseID: string;
|
|
45
|
+
policyVersion?: string;
|
|
46
|
+
}
|
|
47
|
+
/** The decoded value of the recovery-control header. */
|
|
48
|
+
export interface QortexRecoveryControlEnvelope {
|
|
49
|
+
contractVersion: 1;
|
|
50
|
+
operation: QortexRecoveryControlOperation;
|
|
51
|
+
lease: {
|
|
52
|
+
leaseID: string;
|
|
53
|
+
tokenIDs: string[];
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse Qortex's lease usage projection. Every identity and token is bounded,
|
|
58
|
+
* token IDs must be unique across consumed and unused work, and unknown fields
|
|
59
|
+
* are rejected rather than forwarded.
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseRecoveryLeaseUsage(value: unknown): QortexRecoveryLeaseUsage;
|
|
62
|
+
/**
|
|
63
|
+
* Validate a control envelope before it is sent. The operation's lease ID must
|
|
64
|
+
* name the same lease as the token list, and the list stays within Qortex's
|
|
65
|
+
* additional-work limit.
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseRecoveryControlEnvelope(value: unknown): QortexRecoveryControlEnvelope;
|
|
68
|
+
/**
|
|
69
|
+
* Encode a validated control envelope as the base64url header value Qortex
|
|
70
|
+
* expects. Parser bounds keep every valid envelope under the header size limit.
|
|
71
|
+
*/
|
|
72
|
+
export declare function encodeRecoveryControlEnvelope(value: unknown): string;
|
|
73
|
+
/**
|
|
74
|
+
* Decode a recovery-control header value. The encoding must be canonical base64url
|
|
75
|
+
* so that a value cannot be accepted by one parser and rewritten by another.
|
|
76
|
+
*/
|
|
77
|
+
export declare function decodeRecoveryControlHeader(value: string): QortexRecoveryControlEnvelope;
|
|
78
|
+
/** Return a copy of request headers that carries a validated recovery-control envelope. */
|
|
79
|
+
export declare function withRecoveryControlHeader(headers: Record<string, string>, control: unknown): Record<string, string>;
|
|
80
|
+
//# sourceMappingURL=recovery-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-lease.d.ts","sourceRoot":"","sources":["../src/recovery-lease.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,kFAAkF;AAClF,eAAO,MAAM,8BAA8B,+BAA+B,CAAC;AAE3E,mFAAmF;AACnF,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,QAAkB,CAAC;AAO9D,MAAM,MAAM,kCAAkC,GAC1C,iBAAiB,GACjB,kBAAkB,GAClB,cAAc,GACd,YAAY,GACZ,QAAQ,GACR,gBAAgB,CAAC;AAErB,MAAM,MAAM,oBAAoB,GAAG,kCAAkC,GAAG,kBAAkB,CAAC;AAE3F,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kCAAkC,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4FAA4F;AAC5F,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,CAAC,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,0BAA0B,EAAE,CAAC;IACvC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,CAAC,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB,EAAE,MAAM,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wDAAwD;AACxD,MAAM,WAAW,6BAA6B;IAC5C,eAAe,EAAE,CAAC,CAAC;IACnB,SAAS,EAAE,8BAA8B,CAAC;IAC1C,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAChD;AA0FD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAuChF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,6BAA6B,CAgE1F;AAgBD;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,6BAA6B,CAoBxF;AAED,2FAA2F;AAC3F,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qortex's recovery lease wire contract: the control envelope a host sends to
|
|
3
|
+
* bound additional work, and the usage projection Qortex returns for it.
|
|
4
|
+
* QitQore parses and encodes these values only. Hosts allocate token budgets,
|
|
5
|
+
* persist leases, authorize replay, and settle outcomes.
|
|
6
|
+
*/
|
|
7
|
+
/** Request header that carries a base64url-encoded control envelope to Qortex. */
|
|
8
|
+
export const QORTEX_RECOVERY_CONTROL_HEADER = "x-qitqode-recovery-control";
|
|
9
|
+
/** Maximum additional-work tokens in one lease, matching Qortex's public limit. */
|
|
10
|
+
export const MAX_RECOVERY_ADDITIONAL_WORK = 12;
|
|
11
|
+
/** Longest root-operation window Qortex will honor for one dispatch. */
|
|
12
|
+
export const MAX_RECOVERY_ROOT_REMAINING_MS = 15 * 60 * 1_000;
|
|
13
|
+
const MAX_RECOVERY_CONTROL_HEADER_LENGTH = 16_384;
|
|
14
|
+
const MAX_IDENTIFIER_LENGTH = 256;
|
|
15
|
+
const MAX_STAGE_LENGTH = 128;
|
|
16
|
+
const HEADER_VALUE = /^[A-Za-z0-9_-]+$/;
|
|
17
|
+
const RECOVERY_ACTIONS = new Set([
|
|
18
|
+
"initial_dispatch",
|
|
19
|
+
"retry_same_work",
|
|
20
|
+
"changed_approach",
|
|
21
|
+
"continuation",
|
|
22
|
+
"compaction",
|
|
23
|
+
"worker",
|
|
24
|
+
"reconciliation",
|
|
25
|
+
]);
|
|
26
|
+
const CONSUMED_WORK_ACTIONS = new Set([
|
|
27
|
+
"retry_same_work",
|
|
28
|
+
"changed_approach",
|
|
29
|
+
"continuation",
|
|
30
|
+
"compaction",
|
|
31
|
+
"worker",
|
|
32
|
+
"reconciliation",
|
|
33
|
+
]);
|
|
34
|
+
const USAGE_FIELDS = new Set([
|
|
35
|
+
"contractVersion",
|
|
36
|
+
"leaseID",
|
|
37
|
+
"publicOperationID",
|
|
38
|
+
"operationGeneration",
|
|
39
|
+
"workID",
|
|
40
|
+
"attemptID",
|
|
41
|
+
"requestID",
|
|
42
|
+
"routeID",
|
|
43
|
+
"consumed",
|
|
44
|
+
"unusedTokenIDs",
|
|
45
|
+
]);
|
|
46
|
+
const CONSUMED_FIELDS = new Set(["tokenID", "action", "stage"]);
|
|
47
|
+
const ENVELOPE_FIELDS = new Set(["contractVersion", "operation", "lease"]);
|
|
48
|
+
const OPERATION_FIELDS = new Set([
|
|
49
|
+
"contractVersion",
|
|
50
|
+
"publicOperationID",
|
|
51
|
+
"operationGeneration",
|
|
52
|
+
"workID",
|
|
53
|
+
"attemptID",
|
|
54
|
+
"parentWorkID",
|
|
55
|
+
"action",
|
|
56
|
+
"rootDeadlineAt",
|
|
57
|
+
"rootRemainingMsAtDispatch",
|
|
58
|
+
"claimID",
|
|
59
|
+
"leaseID",
|
|
60
|
+
"policyVersion",
|
|
61
|
+
]);
|
|
62
|
+
const LEASE_FIELDS = new Set(["leaseID", "tokenIDs"]);
|
|
63
|
+
function isRecord(value) {
|
|
64
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
65
|
+
}
|
|
66
|
+
function assertKnownFields(value, allowed, label) {
|
|
67
|
+
for (const key of Object.keys(value)) {
|
|
68
|
+
if (!allowed.has(key))
|
|
69
|
+
throw new TypeError(`Qortex ${label} contains an unsupported field`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function boundedString(value, label, maxLength) {
|
|
73
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
|
|
74
|
+
throw new TypeError(`Qortex ${label} has an invalid identifier`);
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
function nonnegativeInteger(value, label) {
|
|
79
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
80
|
+
throw new TypeError(`Qortex ${label} must be a non-negative integer`);
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function uniqueTokenIDs(tokenIDs, label) {
|
|
85
|
+
if (tokenIDs.length > MAX_RECOVERY_ADDITIONAL_WORK) {
|
|
86
|
+
throw new TypeError(`Qortex ${label} exceeds the additional-work limit`);
|
|
87
|
+
}
|
|
88
|
+
if (new Set(tokenIDs).size !== tokenIDs.length) {
|
|
89
|
+
throw new TypeError(`Qortex ${label} token IDs must be unique`);
|
|
90
|
+
}
|
|
91
|
+
return tokenIDs;
|
|
92
|
+
}
|
|
93
|
+
function tokenIDList(value, label) {
|
|
94
|
+
if (!Array.isArray(value) || value.length > MAX_RECOVERY_ADDITIONAL_WORK) {
|
|
95
|
+
throw new TypeError(`Qortex ${label} has an invalid token list`);
|
|
96
|
+
}
|
|
97
|
+
return value.map((item) => boundedString(item, label, MAX_IDENTIFIER_LENGTH));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Parse Qortex's lease usage projection. Every identity and token is bounded,
|
|
101
|
+
* token IDs must be unique across consumed and unused work, and unknown fields
|
|
102
|
+
* are rejected rather than forwarded.
|
|
103
|
+
*/
|
|
104
|
+
export function parseRecoveryLeaseUsage(value) {
|
|
105
|
+
if (!isRecord(value))
|
|
106
|
+
throw new TypeError("Qortex recovery lease usage must be an object");
|
|
107
|
+
assertKnownFields(value, USAGE_FIELDS, "recovery lease usage");
|
|
108
|
+
if (value.contractVersion !== 1) {
|
|
109
|
+
throw new TypeError("Qortex recovery lease usage uses an unsupported contract version");
|
|
110
|
+
}
|
|
111
|
+
if (!Array.isArray(value.consumed) || value.consumed.length > MAX_RECOVERY_ADDITIONAL_WORK) {
|
|
112
|
+
throw new TypeError("Qortex recovery lease usage has an invalid consumed list");
|
|
113
|
+
}
|
|
114
|
+
const consumed = value.consumed.map((item) => {
|
|
115
|
+
if (!isRecord(item))
|
|
116
|
+
throw new TypeError("Qortex recovery lease usage has an invalid consumed entry");
|
|
117
|
+
assertKnownFields(item, CONSUMED_FIELDS, "recovery lease usage consumed entry");
|
|
118
|
+
if (typeof item.action !== "string" || !CONSUMED_WORK_ACTIONS.has(item.action)) {
|
|
119
|
+
throw new TypeError("Qortex recovery lease usage has an invalid consumed action");
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
tokenID: boundedString(item.tokenID, "recovery lease usage tokenID", MAX_IDENTIFIER_LENGTH),
|
|
123
|
+
action: item.action,
|
|
124
|
+
stage: boundedString(item.stage, "recovery lease usage stage", MAX_STAGE_LENGTH),
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
const unusedTokenIDs = tokenIDList(value.unusedTokenIDs, "recovery lease usage unusedTokenIDs");
|
|
128
|
+
uniqueTokenIDs([...consumed.map((item) => item.tokenID), ...unusedTokenIDs], "recovery lease usage");
|
|
129
|
+
return {
|
|
130
|
+
contractVersion: 1,
|
|
131
|
+
leaseID: boundedString(value.leaseID, "recovery lease usage leaseID", MAX_IDENTIFIER_LENGTH),
|
|
132
|
+
publicOperationID: boundedString(value.publicOperationID, "recovery lease usage publicOperationID", MAX_IDENTIFIER_LENGTH),
|
|
133
|
+
operationGeneration: nonnegativeInteger(value.operationGeneration, "recovery lease usage operationGeneration"),
|
|
134
|
+
workID: boundedString(value.workID, "recovery lease usage workID", MAX_IDENTIFIER_LENGTH),
|
|
135
|
+
attemptID: boundedString(value.attemptID, "recovery lease usage attemptID", MAX_IDENTIFIER_LENGTH),
|
|
136
|
+
requestID: boundedString(value.requestID, "recovery lease usage requestID", MAX_IDENTIFIER_LENGTH),
|
|
137
|
+
routeID: boundedString(value.routeID, "recovery lease usage routeID", MAX_IDENTIFIER_LENGTH),
|
|
138
|
+
consumed,
|
|
139
|
+
unusedTokenIDs,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validate a control envelope before it is sent. The operation's lease ID must
|
|
144
|
+
* name the same lease as the token list, and the list stays within Qortex's
|
|
145
|
+
* additional-work limit.
|
|
146
|
+
*/
|
|
147
|
+
export function parseRecoveryControlEnvelope(value) {
|
|
148
|
+
if (!isRecord(value))
|
|
149
|
+
throw new TypeError("Qortex recovery control must be an object");
|
|
150
|
+
assertKnownFields(value, ENVELOPE_FIELDS, "recovery control");
|
|
151
|
+
if (value.contractVersion !== 1) {
|
|
152
|
+
throw new TypeError("Qortex recovery control uses an unsupported contract version");
|
|
153
|
+
}
|
|
154
|
+
if (!isRecord(value.operation))
|
|
155
|
+
throw new TypeError("Qortex recovery control operation must be an object");
|
|
156
|
+
const operation = value.operation;
|
|
157
|
+
assertKnownFields(operation, OPERATION_FIELDS, "recovery control operation");
|
|
158
|
+
if (operation.contractVersion !== 1) {
|
|
159
|
+
throw new TypeError("Qortex recovery control operation uses an unsupported contract version");
|
|
160
|
+
}
|
|
161
|
+
if (typeof operation.action !== "string" || !RECOVERY_ACTIONS.has(operation.action)) {
|
|
162
|
+
throw new TypeError("Qortex recovery control operation has an invalid action");
|
|
163
|
+
}
|
|
164
|
+
if (typeof operation.rootDeadlineAt !== "number" ||
|
|
165
|
+
!Number.isFinite(operation.rootDeadlineAt) ||
|
|
166
|
+
operation.rootDeadlineAt <= 0) {
|
|
167
|
+
throw new TypeError("Qortex recovery control operation has an invalid rootDeadlineAt");
|
|
168
|
+
}
|
|
169
|
+
if (typeof operation.rootRemainingMsAtDispatch !== "number" ||
|
|
170
|
+
!Number.isFinite(operation.rootRemainingMsAtDispatch) ||
|
|
171
|
+
operation.rootRemainingMsAtDispatch < 0 ||
|
|
172
|
+
operation.rootRemainingMsAtDispatch > MAX_RECOVERY_ROOT_REMAINING_MS) {
|
|
173
|
+
throw new TypeError("Qortex recovery control operation has an invalid rootRemainingMsAtDispatch");
|
|
174
|
+
}
|
|
175
|
+
if (!isRecord(value.lease))
|
|
176
|
+
throw new TypeError("Qortex recovery control lease must be an object");
|
|
177
|
+
assertKnownFields(value.lease, LEASE_FIELDS, "recovery control lease");
|
|
178
|
+
const leaseID = boundedString(value.lease.leaseID, "recovery control leaseID", MAX_IDENTIFIER_LENGTH);
|
|
179
|
+
const operationLeaseID = boundedString(operation.leaseID, "recovery control operation leaseID", MAX_IDENTIFIER_LENGTH);
|
|
180
|
+
if (operationLeaseID !== leaseID) {
|
|
181
|
+
throw new TypeError("Qortex recovery control lease ID must match the operation");
|
|
182
|
+
}
|
|
183
|
+
const tokenIDs = uniqueTokenIDs(tokenIDList(value.lease.tokenIDs, "recovery control tokenIDs"), "recovery control");
|
|
184
|
+
return {
|
|
185
|
+
contractVersion: 1,
|
|
186
|
+
operation: {
|
|
187
|
+
contractVersion: 1,
|
|
188
|
+
publicOperationID: boundedString(operation.publicOperationID, "recovery control publicOperationID", MAX_IDENTIFIER_LENGTH),
|
|
189
|
+
operationGeneration: nonnegativeInteger(operation.operationGeneration, "recovery control operationGeneration"),
|
|
190
|
+
workID: boundedString(operation.workID, "recovery control workID", MAX_IDENTIFIER_LENGTH),
|
|
191
|
+
attemptID: boundedString(operation.attemptID, "recovery control attemptID", MAX_IDENTIFIER_LENGTH),
|
|
192
|
+
...(operation.parentWorkID === undefined
|
|
193
|
+
? {}
|
|
194
|
+
: { parentWorkID: boundedString(operation.parentWorkID, "recovery control parentWorkID", MAX_IDENTIFIER_LENGTH) }),
|
|
195
|
+
action: operation.action,
|
|
196
|
+
rootDeadlineAt: operation.rootDeadlineAt,
|
|
197
|
+
rootRemainingMsAtDispatch: operation.rootRemainingMsAtDispatch,
|
|
198
|
+
...(operation.claimID === undefined
|
|
199
|
+
? {}
|
|
200
|
+
: { claimID: boundedString(operation.claimID, "recovery control claimID", MAX_IDENTIFIER_LENGTH) }),
|
|
201
|
+
leaseID,
|
|
202
|
+
...(operation.policyVersion === undefined
|
|
203
|
+
? {}
|
|
204
|
+
: { policyVersion: boundedString(operation.policyVersion, "recovery control policyVersion", MAX_IDENTIFIER_LENGTH) }),
|
|
205
|
+
},
|
|
206
|
+
lease: { leaseID, tokenIDs },
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function base64UrlEncode(text) {
|
|
210
|
+
const bytes = new TextEncoder().encode(text);
|
|
211
|
+
let binary = "";
|
|
212
|
+
for (const byte of bytes)
|
|
213
|
+
binary += String.fromCharCode(byte);
|
|
214
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
215
|
+
}
|
|
216
|
+
function base64UrlDecode(value) {
|
|
217
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
|
|
218
|
+
const binary = atob(padded);
|
|
219
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
220
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Encode a validated control envelope as the base64url header value Qortex
|
|
224
|
+
* expects. Parser bounds keep every valid envelope under the header size limit.
|
|
225
|
+
*/
|
|
226
|
+
export function encodeRecoveryControlEnvelope(value) {
|
|
227
|
+
return base64UrlEncode(JSON.stringify(parseRecoveryControlEnvelope(value)));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Decode a recovery-control header value. The encoding must be canonical base64url
|
|
231
|
+
* so that a value cannot be accepted by one parser and rewritten by another.
|
|
232
|
+
*/
|
|
233
|
+
export function decodeRecoveryControlHeader(value) {
|
|
234
|
+
if (typeof value !== "string" ||
|
|
235
|
+
value.length === 0 ||
|
|
236
|
+
value.length > MAX_RECOVERY_CONTROL_HEADER_LENGTH ||
|
|
237
|
+
!HEADER_VALUE.test(value)) {
|
|
238
|
+
throw new TypeError("Qortex recovery control header is invalid");
|
|
239
|
+
}
|
|
240
|
+
let decoded;
|
|
241
|
+
try {
|
|
242
|
+
decoded = JSON.parse(base64UrlDecode(value));
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
throw new TypeError("Qortex recovery control header is invalid");
|
|
246
|
+
}
|
|
247
|
+
const envelope = parseRecoveryControlEnvelope(decoded);
|
|
248
|
+
if (base64UrlEncode(JSON.stringify(envelope)) !== value) {
|
|
249
|
+
throw new TypeError("Qortex recovery control header is not canonically encoded");
|
|
250
|
+
}
|
|
251
|
+
return envelope;
|
|
252
|
+
}
|
|
253
|
+
/** Return a copy of request headers that carries a validated recovery-control envelope. */
|
|
254
|
+
export function withRecoveryControlHeader(headers, control) {
|
|
255
|
+
return { ...headers, [QORTEX_RECOVERY_CONTROL_HEADER]: encodeRecoveryControlEnvelope(control) };
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=recovery-lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-lease.js","sourceRoot":"","sources":["../src/recovery-lease.ts"],"names":[],"mappings":"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"}
|