@connextar/house 0.10.0 → 0.11.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/README.md +447 -0
- package/dist/jobs/counts.d.ts +82 -0
- package/dist/jobs/counts.d.ts.map +1 -0
- package/dist/jobs/counts.js +112 -0
- package/dist/jobs/counts.js.map +1 -0
- package/dist/jobs/cron-auth.d.ts +44 -0
- package/dist/jobs/cron-auth.d.ts.map +1 -0
- package/dist/jobs/cron-auth.js +20 -0
- package/dist/jobs/cron-auth.js.map +1 -0
- package/dist/jobs/health.d.ts +157 -0
- package/dist/jobs/health.d.ts.map +1 -0
- package/dist/jobs/health.js +146 -0
- package/dist/jobs/health.js.map +1 -0
- package/dist/jobs/index.d.ts +26 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +26 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/job-health-list.d.ts +66 -0
- package/dist/jobs/job-health-list.d.ts.map +1 -0
- package/dist/jobs/job-health-list.js +115 -0
- package/dist/jobs/job-health-list.js.map +1 -0
- package/dist/jobs/react-index.d.ts +19 -0
- package/dist/jobs/react-index.d.ts.map +1 -0
- package/dist/jobs/react-index.js +18 -0
- package/dist/jobs/react-index.js.map +1 -0
- package/dist/jobs/registry.d.ts +104 -0
- package/dist/jobs/registry.d.ts.map +1 -0
- package/dist/jobs/registry.js +72 -0
- package/dist/jobs/registry.js.map +1 -0
- package/dist/jobs/scheduler.d.ts +89 -0
- package/dist/jobs/scheduler.d.ts.map +1 -0
- package/dist/jobs/scheduler.js +282 -0
- package/dist/jobs/scheduler.js.map +1 -0
- package/dist/jobs/store.d.ts +94 -0
- package/dist/jobs/store.d.ts.map +1 -0
- package/dist/jobs/store.js +56 -0
- package/dist/jobs/store.js.map +1 -0
- package/dist/jobs/windows.d.ts +66 -0
- package/dist/jobs/windows.d.ts.map +1 -0
- package/dist/jobs/windows.js +130 -0
- package/dist/jobs/windows.js.map +1 -0
- package/package.json +9 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counts.js","sourceRoot":"","sources":["../../src/jobs/counts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a request may run the scheduled jobs: the shared `CRON_SECRET`, as
|
|
3
|
+
* Vercel's cron sends it (`Authorization: Bearer <secret>`).
|
|
4
|
+
*
|
|
5
|
+
* Both apps wrote this, the same way in substance. The union keeps each one's
|
|
6
|
+
* better half:
|
|
7
|
+
*
|
|
8
|
+
* - **An unset secret refuses everything (503)** rather than running
|
|
9
|
+
* unauthenticated. Both.
|
|
10
|
+
* - **Compared as SHA-256 digests with `timingSafeEqual`** (Quickie). Equal
|
|
11
|
+
* lengths whatever was sent, so the comparison is constant-time and leaks not
|
|
12
|
+
* even the secret's length. AltEd compared the raw bytes after a length check.
|
|
13
|
+
* - **A committed development secret is refused in production** (Quickie). Next
|
|
14
|
+
* loads `.env` in production too, so a host that forgets its own value would
|
|
15
|
+
* otherwise run on the one in the repository.
|
|
16
|
+
* - **No secret in the address unless asked for** (AltEd). `?secret=` lands in
|
|
17
|
+
* every request log on the way; a route only Vercel calls has no use for it.
|
|
18
|
+
* Quickie accepted it everywhere, AltEd on the tick. Off by default here.
|
|
19
|
+
* - **The Bearer scheme is required.** Quickie's check stripped an optional
|
|
20
|
+
* prefix, so a bare secret in the header also passed.
|
|
21
|
+
*
|
|
22
|
+
* Returns a decision, not a `Response`: each app answers in its own envelope.
|
|
23
|
+
*/
|
|
24
|
+
export type CronAuthResult = {
|
|
25
|
+
ok: true;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
status: 401 | 503;
|
|
29
|
+
message: string;
|
|
30
|
+
};
|
|
31
|
+
export interface CronAuthOptions {
|
|
32
|
+
/** The secret. Default `process.env.CRON_SECRET`. */
|
|
33
|
+
secret?: string;
|
|
34
|
+
/** Accept `?secret=` from a scheduler that can only call an address. Default `false`. */
|
|
35
|
+
allowQuery?: boolean;
|
|
36
|
+
/** Values that are public — committed to the repository — and so refused in production. */
|
|
37
|
+
publicSecrets?: readonly string[];
|
|
38
|
+
/** Default `process.env.NODE_ENV === "production"`. */
|
|
39
|
+
production?: boolean;
|
|
40
|
+
/** What the refusal calls this endpoint: "Cron", "The harvest". Default "Cron". */
|
|
41
|
+
label?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function checkCronRequest(request: Request, options?: CronAuthOptions): CronAuthResult;
|
|
44
|
+
//# sourceMappingURL=cron-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-auth.d.ts","sourceRoot":"","sources":["../../src/jobs/cron-auth.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB,GAAG,cAAc,CAiBhG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
+
const digest = (value) => createHash("sha256").update(value).digest();
|
|
3
|
+
export function checkCronRequest(request, options = {}) {
|
|
4
|
+
const label = options.label ?? "Cron";
|
|
5
|
+
const secret = options.secret ?? process.env.CRON_SECRET ?? "";
|
|
6
|
+
if (!secret)
|
|
7
|
+
return { ok: false, status: 503, message: `${label} is not configured (CRON_SECRET unset).` };
|
|
8
|
+
const production = options.production ?? process.env.NODE_ENV === "production";
|
|
9
|
+
if (production && options.publicSecrets?.includes(secret)) {
|
|
10
|
+
return { ok: false, status: 503, message: `${label} is not configured (CRON_SECRET is the development value).` };
|
|
11
|
+
}
|
|
12
|
+
const header = request.headers.get("authorization") ?? "";
|
|
13
|
+
const bearer = /^Bearer\s+(.+)$/i.exec(header)?.[1];
|
|
14
|
+
const provided = bearer ?? (options.allowQuery ? (new URL(request.url).searchParams.get("secret") ?? undefined) : undefined);
|
|
15
|
+
if (!provided || !timingSafeEqual(digest(provided), digest(secret))) {
|
|
16
|
+
return { ok: false, status: 401, message: "Unauthorized" };
|
|
17
|
+
}
|
|
18
|
+
return { ok: true };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cron-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-auth.js","sourceRoot":"","sources":["../../src/jobs/cron-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAwC1D,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;AAE9E,MAAM,UAAU,gBAAgB,CAAC,OAAgB,EAAE,UAA2B,EAAE;IAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAC/D,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK,yCAAyC,EAAE,CAAC;IAC3G,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;IAC/E,IAAI,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK,4DAA4D,EAAE,CAAC;IACnH,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,QAAQ,GACZ,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC9G,IAAI,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QACpE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type CountFormatOptions, type CountLine } from "./counts.js";
|
|
2
|
+
import type { AnyJob, RunNowScope } from "./registry.js";
|
|
3
|
+
import type { JobRunRecord, JobSwitchState } from "./store.js";
|
|
4
|
+
/**
|
|
5
|
+
* A job's health — derived every time it is shown, never stored.
|
|
6
|
+
*
|
|
7
|
+
* A stored status is a second copy of the truth that drifts from the first.
|
|
8
|
+
* Health here is a function of the ledger, the switch and the clock, so the
|
|
9
|
+
* card cannot say "Healthy" about a job whose last run failed an hour ago.
|
|
10
|
+
*
|
|
11
|
+
* Six states, in the order they win:
|
|
12
|
+
*
|
|
13
|
+
* 1. **paused** — switched off. Whatever the runs say, nothing new will start.
|
|
14
|
+
* 2. **never-run** — no run this viewer can see.
|
|
15
|
+
* 3. **running** — the latest run has not finished, and is inside its timeout.
|
|
16
|
+
* 4. **failed** — the latest run failed, or started and never finished. Both
|
|
17
|
+
* apps showed a run still in progress as "Errored", because an unfinished
|
|
18
|
+
* row has `ok = false`; and a run cut off by the platform's time limit stayed
|
|
19
|
+
* that way for ever with no message at all. Past its timeout it is a failure
|
|
20
|
+
* that says so.
|
|
21
|
+
* 5. **stale** — no successful *whole* run for longer than the threshold (a
|
|
22
|
+
* run exactly at the threshold is still healthy). A tenant's own Run now
|
|
23
|
+
* sweeps one tenant, so it proves nothing about the schedule and does not
|
|
24
|
+
* reset the clock — in Quickie it did, so one owner's click made a job look
|
|
25
|
+
* healthy to everyone.
|
|
26
|
+
* 6. **healthy**.
|
|
27
|
+
*/
|
|
28
|
+
export type JobHealthState = "paused" | "never-run" | "running" | "failed" | "stale" | "healthy";
|
|
29
|
+
export type JobHealth = {
|
|
30
|
+
state: "paused";
|
|
31
|
+
} | {
|
|
32
|
+
state: "never-run";
|
|
33
|
+
} | {
|
|
34
|
+
state: "running";
|
|
35
|
+
since: string;
|
|
36
|
+
} | {
|
|
37
|
+
state: "failed";
|
|
38
|
+
at: string;
|
|
39
|
+
error: string | null;
|
|
40
|
+
unfinished: boolean;
|
|
41
|
+
} | {
|
|
42
|
+
state: "stale";
|
|
43
|
+
lastSuccessAt: string | null;
|
|
44
|
+
thresholdMs: number;
|
|
45
|
+
} | {
|
|
46
|
+
state: "healthy";
|
|
47
|
+
lastSuccessAt: string;
|
|
48
|
+
};
|
|
49
|
+
/** The fields of a run that health reads. */
|
|
50
|
+
export interface RunFacts {
|
|
51
|
+
startedAt: Date;
|
|
52
|
+
finishedAt: Date | null;
|
|
53
|
+
ok: boolean;
|
|
54
|
+
error: string | null;
|
|
55
|
+
}
|
|
56
|
+
export interface HealthInput {
|
|
57
|
+
paused: boolean;
|
|
58
|
+
/** The latest run the viewer can see. */
|
|
59
|
+
latest: RunFacts | null;
|
|
60
|
+
/** The latest successful run over every tenant — the one staleness is measured from. */
|
|
61
|
+
lastWholeSuccess: RunFacts | null;
|
|
62
|
+
staleAfterMs: number | null;
|
|
63
|
+
timeoutMs: number;
|
|
64
|
+
now: Date;
|
|
65
|
+
}
|
|
66
|
+
export declare function deriveHealth(input: HealthInput): JobHealth;
|
|
67
|
+
/**
|
|
68
|
+
* Who is looking. A platform viewer (AltEd's administrators, Quickie's
|
|
69
|
+
* operators) may switch jobs and sees every sweep's detail; a tenant viewer
|
|
70
|
+
* (Quickie's owners) sees their own Run now results in full, and of a sweep
|
|
71
|
+
* over every tenant only whether it ran and when.
|
|
72
|
+
*/
|
|
73
|
+
export interface JobAudience {
|
|
74
|
+
platform: boolean;
|
|
75
|
+
tenantId?: string | null;
|
|
76
|
+
}
|
|
77
|
+
/** One run, as the card shows it. Dates are ISO strings, so it crosses from a server component intact. */
|
|
78
|
+
export interface JobRunView {
|
|
79
|
+
startedAt: string;
|
|
80
|
+
finishedAt: string | null;
|
|
81
|
+
ok: boolean;
|
|
82
|
+
trigger: "schedule" | "manual";
|
|
83
|
+
by: string | null;
|
|
84
|
+
/** A tenant's Run now: it swept one tenant, not all. */
|
|
85
|
+
tenantScoped: boolean;
|
|
86
|
+
counts: CountLine[];
|
|
87
|
+
error: string | null;
|
|
88
|
+
/**
|
|
89
|
+
* Counts and error left out: a sweep over every tenant, seen by one tenant.
|
|
90
|
+
* Quickie showed each owner the platform-wide ledger, so "412 emails sent"
|
|
91
|
+
* read as theirs, and an error from another organisation's data was on every
|
|
92
|
+
* owner's settings page.
|
|
93
|
+
*/
|
|
94
|
+
withheld: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** A job as the health screen draws it — plain data, every count already in words. */
|
|
97
|
+
export interface JobView {
|
|
98
|
+
id: string;
|
|
99
|
+
label: string;
|
|
100
|
+
cadence: string;
|
|
101
|
+
schedule: "tick" | "own";
|
|
102
|
+
staleAfterMs: number | null;
|
|
103
|
+
health: JobHealth;
|
|
104
|
+
/** Health with the switch ignored, so the badge is right the moment someone switches it back on. */
|
|
105
|
+
healthIfOn: JobHealth;
|
|
106
|
+
paused: boolean;
|
|
107
|
+
switchedAt: string | null;
|
|
108
|
+
switchedBy: string | null;
|
|
109
|
+
/** This viewer may switch it. */
|
|
110
|
+
canSwitch: boolean;
|
|
111
|
+
/** This viewer may press Run now, and what it would sweep. */
|
|
112
|
+
runNow: RunNowScope | null;
|
|
113
|
+
lastRun: JobRunView | null;
|
|
114
|
+
lastSuccess: JobRunView | null;
|
|
115
|
+
}
|
|
116
|
+
/** What the view needs from the store for one job. */
|
|
117
|
+
export interface JobFacts {
|
|
118
|
+
switch: JobSwitchState | null;
|
|
119
|
+
latest: JobRunRecord | null;
|
|
120
|
+
lastWholeSuccess: JobRunRecord | null;
|
|
121
|
+
lastVisibleSuccess: JobRunRecord | null;
|
|
122
|
+
}
|
|
123
|
+
export interface JobViewOptions extends CountFormatOptions {
|
|
124
|
+
now: Date;
|
|
125
|
+
}
|
|
126
|
+
export declare function effectiveTimeout(job: AnyJob, fallback: number): number;
|
|
127
|
+
/** Whether this viewer may press Run now on this job. */
|
|
128
|
+
export declare function runNowFor(job: AnyJob, audience: JobAudience): RunNowScope | null;
|
|
129
|
+
export declare function buildJobView(job: AnyJob, facts: JobFacts, audience: JobAudience, options: JobViewOptions & {
|
|
130
|
+
timeoutMs: number;
|
|
131
|
+
}): JobView;
|
|
132
|
+
export interface WhenOptions {
|
|
133
|
+
locale?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Whose clock. Default `Europe/London`. Never the runtime's own: the card is
|
|
136
|
+
* drawn on a server in UTC and again in a browser in BST, and two different
|
|
137
|
+
* times in one element is a hydration error.
|
|
138
|
+
*/
|
|
139
|
+
timeZone?: string;
|
|
140
|
+
}
|
|
141
|
+
/** "30 Sept 2026, 14:05". */
|
|
142
|
+
export declare function formatWhen(iso: string, options?: WhenOptions): string;
|
|
143
|
+
/** "29 Sept 2026". */
|
|
144
|
+
export declare function formatDay(iso: string, options?: WhenOptions): string;
|
|
145
|
+
export interface HealthWords {
|
|
146
|
+
label: string;
|
|
147
|
+
/** A sentence under the badge, or `null` when the badge says it all. */
|
|
148
|
+
detail: string | null;
|
|
149
|
+
tone: "good" | "neutral" | "warning" | "bad";
|
|
150
|
+
}
|
|
151
|
+
/** The badge and the sentence under it. */
|
|
152
|
+
export declare function describeHealth(health: JobHealth, options?: WhenOptions): HealthWords;
|
|
153
|
+
/** "Paused 29 Sept 2026 by AltEd Admin", "Turned back on …", or nothing if it was never switched. */
|
|
154
|
+
export declare function describeSwitch(view: Pick<JobView, "paused" | "switchedAt" | "switchedBy">, options?: WhenOptions): string | null;
|
|
155
|
+
/** "Last run 30 Sept 2026, 14:05 · Run now by Ann Lee". */
|
|
156
|
+
export declare function describeRun(run: JobRunView, prefix: string, options?: WhenOptions): string;
|
|
157
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/jobs/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { countLines, describeSpan } from "./counts.js";
|
|
2
|
+
import { isManualKey } from "./windows.js";
|
|
3
|
+
export function deriveHealth(input) {
|
|
4
|
+
const { latest, lastWholeSuccess, now } = input;
|
|
5
|
+
if (input.paused)
|
|
6
|
+
return { state: "paused" };
|
|
7
|
+
if (!latest && !lastWholeSuccess)
|
|
8
|
+
return { state: "never-run" };
|
|
9
|
+
if (latest && !latest.finishedAt) {
|
|
10
|
+
if (now.getTime() - latest.startedAt.getTime() <= input.timeoutMs) {
|
|
11
|
+
return { state: "running", since: latest.startedAt.toISOString() };
|
|
12
|
+
}
|
|
13
|
+
return { state: "failed", at: latest.startedAt.toISOString(), error: null, unfinished: true };
|
|
14
|
+
}
|
|
15
|
+
if (latest && !latest.ok) {
|
|
16
|
+
return { state: "failed", at: latest.startedAt.toISOString(), error: latest.error, unfinished: false };
|
|
17
|
+
}
|
|
18
|
+
if (input.staleAfterMs !== null &&
|
|
19
|
+
(!lastWholeSuccess || now.getTime() - lastWholeSuccess.startedAt.getTime() > input.staleAfterMs)) {
|
|
20
|
+
return {
|
|
21
|
+
state: "stale",
|
|
22
|
+
lastSuccessAt: lastWholeSuccess?.startedAt.toISOString() ?? null,
|
|
23
|
+
thresholdMs: input.staleAfterMs,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const success = lastWholeSuccess ?? latest;
|
|
27
|
+
return { state: "healthy", lastSuccessAt: success.startedAt.toISOString() };
|
|
28
|
+
}
|
|
29
|
+
export function effectiveTimeout(job, fallback) {
|
|
30
|
+
return job.timeoutMs ?? fallback;
|
|
31
|
+
}
|
|
32
|
+
/** Whether this viewer may press Run now on this job. */
|
|
33
|
+
export function runNowFor(job, audience) {
|
|
34
|
+
if (!job.runNow)
|
|
35
|
+
return null;
|
|
36
|
+
if (job.runNow.scope === "tenant")
|
|
37
|
+
return audience.tenantId ? "tenant" : null;
|
|
38
|
+
return audience.platform ? "platform" : null;
|
|
39
|
+
}
|
|
40
|
+
function runView(job, run, audience, options) {
|
|
41
|
+
const withheld = !audience.platform && run.tenantId === null;
|
|
42
|
+
return {
|
|
43
|
+
startedAt: run.startedAt.toISOString(),
|
|
44
|
+
finishedAt: run.finishedAt?.toISOString() ?? null,
|
|
45
|
+
ok: run.ok,
|
|
46
|
+
trigger: isManualKey(run.windowKey) ? "manual" : "schedule",
|
|
47
|
+
by: run.by,
|
|
48
|
+
tenantScoped: run.tenantId !== null,
|
|
49
|
+
counts: withheld ? [] : countLines(job.counts, run.counts, options),
|
|
50
|
+
error: withheld ? null : run.error,
|
|
51
|
+
withheld,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function buildJobView(job, facts, audience, options) {
|
|
55
|
+
const switchable = job.switchable ?? true;
|
|
56
|
+
const paused = switchable && Boolean(facts.switch?.paused);
|
|
57
|
+
const lastRun = facts.latest ? runView(job, facts.latest, audience, options) : null;
|
|
58
|
+
const input = {
|
|
59
|
+
latest: facts.latest,
|
|
60
|
+
lastWholeSuccess: facts.lastWholeSuccess,
|
|
61
|
+
staleAfterMs: job.staleAfterMs,
|
|
62
|
+
timeoutMs: effectiveTimeout(job, options.timeoutMs),
|
|
63
|
+
now: options.now,
|
|
64
|
+
};
|
|
65
|
+
const healthIfOn = deriveHealth({ ...input, paused: false });
|
|
66
|
+
// A withheld failure keeps its state and loses its words.
|
|
67
|
+
const redact = (health) => health.state === "failed" && lastRun?.withheld ? { ...health, error: null } : health;
|
|
68
|
+
return {
|
|
69
|
+
id: job.id,
|
|
70
|
+
label: job.label,
|
|
71
|
+
cadence: job.cadence,
|
|
72
|
+
schedule: job.schedule ?? "tick",
|
|
73
|
+
staleAfterMs: job.staleAfterMs,
|
|
74
|
+
health: redact(paused ? { state: "paused" } : healthIfOn),
|
|
75
|
+
healthIfOn: redact(healthIfOn),
|
|
76
|
+
paused,
|
|
77
|
+
switchedAt: switchable ? (facts.switch?.at?.toISOString() ?? null) : null,
|
|
78
|
+
switchedBy: switchable ? (facts.switch?.by ?? null) : null,
|
|
79
|
+
canSwitch: switchable && audience.platform,
|
|
80
|
+
runNow: runNowFor(job, audience),
|
|
81
|
+
lastRun,
|
|
82
|
+
lastSuccess: facts.lastVisibleSuccess ? runView(job, facts.lastVisibleSuccess, audience, options) : null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** "30 Sept 2026, 14:05". */
|
|
86
|
+
export function formatWhen(iso, options = {}) {
|
|
87
|
+
return new Intl.DateTimeFormat(options.locale ?? "en-GB", {
|
|
88
|
+
day: "numeric",
|
|
89
|
+
month: "short",
|
|
90
|
+
year: "numeric",
|
|
91
|
+
hour: "2-digit",
|
|
92
|
+
minute: "2-digit",
|
|
93
|
+
timeZone: options.timeZone ?? "Europe/London",
|
|
94
|
+
}).format(new Date(iso));
|
|
95
|
+
}
|
|
96
|
+
/** "29 Sept 2026". */
|
|
97
|
+
export function formatDay(iso, options = {}) {
|
|
98
|
+
return new Intl.DateTimeFormat(options.locale ?? "en-GB", {
|
|
99
|
+
day: "numeric",
|
|
100
|
+
month: "short",
|
|
101
|
+
year: "numeric",
|
|
102
|
+
timeZone: options.timeZone ?? "Europe/London",
|
|
103
|
+
}).format(new Date(iso));
|
|
104
|
+
}
|
|
105
|
+
/** The badge and the sentence under it. */
|
|
106
|
+
export function describeHealth(health, options = {}) {
|
|
107
|
+
switch (health.state) {
|
|
108
|
+
case "paused":
|
|
109
|
+
return { label: "Paused", detail: null, tone: "neutral" };
|
|
110
|
+
case "never-run":
|
|
111
|
+
return { label: "Never run", detail: "No runs recorded yet.", tone: "neutral" };
|
|
112
|
+
case "running":
|
|
113
|
+
return { label: "Running", detail: `Started ${formatWhen(health.since, options)}.`, tone: "neutral" };
|
|
114
|
+
case "failed":
|
|
115
|
+
return {
|
|
116
|
+
label: "Failed",
|
|
117
|
+
detail: health.unfinished
|
|
118
|
+
? `Started ${formatWhen(health.at, options)} and never finished — it was probably cut off.`
|
|
119
|
+
: (health.error ?? "The last run failed."),
|
|
120
|
+
tone: "bad",
|
|
121
|
+
};
|
|
122
|
+
case "stale":
|
|
123
|
+
return {
|
|
124
|
+
label: "Stale",
|
|
125
|
+
detail: health.lastSuccessAt
|
|
126
|
+
? `No successful run in over ${describeSpan(health.thresholdMs)} — the last was ${formatWhen(health.lastSuccessAt, options)}.`
|
|
127
|
+
: `No successful run on its schedule yet; one is expected every ${describeSpan(health.thresholdMs)}.`,
|
|
128
|
+
tone: "warning",
|
|
129
|
+
};
|
|
130
|
+
case "healthy":
|
|
131
|
+
return { label: "Healthy", detail: null, tone: "good" };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** "Paused 29 Sept 2026 by AltEd Admin", "Turned back on …", or nothing if it was never switched. */
|
|
135
|
+
export function describeSwitch(view, options = {}) {
|
|
136
|
+
if (!view.switchedAt)
|
|
137
|
+
return view.paused ? "Paused" : null;
|
|
138
|
+
const by = view.switchedBy ? ` by ${view.switchedBy}` : "";
|
|
139
|
+
return `${view.paused ? "Paused" : "Turned back on"} ${formatDay(view.switchedAt, options)}${by}`;
|
|
140
|
+
}
|
|
141
|
+
/** "Last run 30 Sept 2026, 14:05 · Run now by Ann Lee". */
|
|
142
|
+
export function describeRun(run, prefix, options = {}) {
|
|
143
|
+
const when = `${prefix} ${formatWhen(run.startedAt, options)}`;
|
|
144
|
+
return run.trigger === "manual" ? `${when} · Run now${run.by ? ` by ${run.by}` : ""}` : when;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/jobs/health.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@connextar/house/jobs` — scheduled jobs: declared once, run once per
|
|
3
|
+
* window, switched off and on by name, and honest about their health.
|
|
4
|
+
*
|
|
5
|
+
* AltEd and Quickie each wrote this, from the same seed, and each went on to
|
|
6
|
+
* prove something the other had not: AltEd that a job must be switchable with a
|
|
7
|
+
* name and a date against it, and that some jobs run on their own clock;
|
|
8
|
+
* Quickie that Run now must be fenced to the caller's own tenant. Both printed
|
|
9
|
+
* a job's result as its variable names. This is the union, with that made
|
|
10
|
+
* impossible: a count reaches the screen only through its declaration.
|
|
11
|
+
*
|
|
12
|
+
* Server code. It owns no schema — the app implements `JobStore` over its own
|
|
13
|
+
* table (the README has the Prisma model and adapter) — and it imports no
|
|
14
|
+
* framework: the only thing it reaches for is `node:crypto`, in the tick
|
|
15
|
+
* route's secret check. The health list is `@connextar/house/jobs/react`,
|
|
16
|
+
* which re-exports the words and types a client component needs, so nothing
|
|
17
|
+
* in the browser ever imports this entry.
|
|
18
|
+
*/
|
|
19
|
+
export { checkCronRequest, type CronAuthOptions, type CronAuthResult } from "./cron-auth.js";
|
|
20
|
+
export { countLines, countsSummary, declaredCounts, describeSpan, formatCount, formatDuration, formatMoney, type CountDeclaration, type CountDeclarations, type CountFormatOptions, type CountKind, type CountLabel, type CountLine, type CountValues, } from "./counts.js";
|
|
21
|
+
export { buildJobView, deriveHealth, describeHealth, describeRun, describeSwitch, formatDay, formatWhen, runNowFor, type HealthInput, type HealthWords, type JobAudience, type JobFacts, type JobHealth, type JobHealthState, type JobRunView, type JobView, type RunFacts, type WhenOptions, } from "./health.js";
|
|
22
|
+
export { DEFAULT_COOLDOWN_MS, DEFAULT_TIMEOUT_MS, MAX_JOB_ID, MAX_WINDOW_KEY, defineJob, defineJobs, jobDefinitionProblems, type AnyJob, type JobActor, type JobContext, type JobDefinition, type RunNowRule, type RunNowScope, } from "./registry.js";
|
|
23
|
+
export { createScheduler, refusalStatus, summariseTick, type RunNowCaller, type RunNowOutcome, type RunNowRefusal, type Scheduler, type SchedulerOptions, type SwitchCaller, type SwitchOutcome, type SwitchRefusal, type TickResult, type TickStatus, } from "./scheduler.js";
|
|
24
|
+
export { createMemoryJobStore, pausedFromStored, type JobRunClaim, type JobRunOutcome, type JobRunQuery, type JobRunRecord, type JobStore, type JobSwitchChange, type JobSwitchState, } from "./store.js";
|
|
25
|
+
export { MANUAL_KEY_PREFIX, daily, everyHours, hourly, isManualKey, monthly, weekly, type CalendarWindowOptions, type JobWindow, } from "./windows.js";
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,cAAc,EACd,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,UAAU,EACV,SAAS,EACT,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,EACV,qBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,EACL,UAAU,EACV,MAAM,EACN,WAAW,EACX,OAAO,EACP,MAAM,EACN,KAAK,qBAAqB,EAC1B,KAAK,SAAS,GACf,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@connextar/house/jobs` — scheduled jobs: declared once, run once per
|
|
3
|
+
* window, switched off and on by name, and honest about their health.
|
|
4
|
+
*
|
|
5
|
+
* AltEd and Quickie each wrote this, from the same seed, and each went on to
|
|
6
|
+
* prove something the other had not: AltEd that a job must be switchable with a
|
|
7
|
+
* name and a date against it, and that some jobs run on their own clock;
|
|
8
|
+
* Quickie that Run now must be fenced to the caller's own tenant. Both printed
|
|
9
|
+
* a job's result as its variable names. This is the union, with that made
|
|
10
|
+
* impossible: a count reaches the screen only through its declaration.
|
|
11
|
+
*
|
|
12
|
+
* Server code. It owns no schema — the app implements `JobStore` over its own
|
|
13
|
+
* table (the README has the Prisma model and adapter) — and it imports no
|
|
14
|
+
* framework: the only thing it reaches for is `node:crypto`, in the tick
|
|
15
|
+
* route's secret check. The health list is `@connextar/house/jobs/react`,
|
|
16
|
+
* which re-exports the words and types a client component needs, so nothing
|
|
17
|
+
* in the browser ever imports this entry.
|
|
18
|
+
*/
|
|
19
|
+
export { checkCronRequest } from "./cron-auth.js";
|
|
20
|
+
export { countLines, countsSummary, declaredCounts, describeSpan, formatCount, formatDuration, formatMoney, } from "./counts.js";
|
|
21
|
+
export { buildJobView, deriveHealth, describeHealth, describeRun, describeSwitch, formatDay, formatWhen, runNowFor, } from "./health.js";
|
|
22
|
+
export { DEFAULT_COOLDOWN_MS, DEFAULT_TIMEOUT_MS, MAX_JOB_ID, MAX_WINDOW_KEY, defineJob, defineJobs, jobDefinitionProblems, } from "./registry.js";
|
|
23
|
+
export { createScheduler, refusalStatus, summariseTick, } from "./scheduler.js";
|
|
24
|
+
export { createMemoryJobStore, pausedFromStored, } from "./store.js";
|
|
25
|
+
export { MANUAL_KEY_PREFIX, daily, everyHours, hourly, isManualKey, monthly, weekly, } from "./windows.js";
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,gBAAgB,EAA6C,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,cAAc,EACd,WAAW,GAQZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,UAAU,EACV,SAAS,GAWV,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,SAAS,EACT,UAAU,EACV,qBAAqB,GAOtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,GAWd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,GAQjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,EACL,UAAU,EACV,MAAM,EACN,WAAW,EACX,OAAO,EACP,MAAM,GAGP,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type JobView, type WhenOptions } from "./health.js";
|
|
3
|
+
/** Every element the list draws. Each value replaces the default for that part. */
|
|
4
|
+
export interface JobHealthClassNames {
|
|
5
|
+
list: string;
|
|
6
|
+
empty: string;
|
|
7
|
+
row: string;
|
|
8
|
+
body: string;
|
|
9
|
+
heading: string;
|
|
10
|
+
label: string;
|
|
11
|
+
badge: string;
|
|
12
|
+
badgeGood: string;
|
|
13
|
+
badgeNeutral: string;
|
|
14
|
+
badgeWarning: string;
|
|
15
|
+
badgeBad: string;
|
|
16
|
+
meta: string;
|
|
17
|
+
detail: string;
|
|
18
|
+
error: string;
|
|
19
|
+
counts: string;
|
|
20
|
+
switched: string;
|
|
21
|
+
actions: string;
|
|
22
|
+
runNow: string;
|
|
23
|
+
switch: string;
|
|
24
|
+
switchOn: string;
|
|
25
|
+
switchOff: string;
|
|
26
|
+
thumb: string;
|
|
27
|
+
thumbOn: string;
|
|
28
|
+
thumbOff: string;
|
|
29
|
+
}
|
|
30
|
+
/** The house look, on the shared theme tokens. */
|
|
31
|
+
export declare const JOB_HEALTH_CLASS_NAMES: JobHealthClassNames;
|
|
32
|
+
export interface JobHealthListProps extends WhenOptions {
|
|
33
|
+
/** From `scheduler.views(audience)` on the server. */
|
|
34
|
+
jobs: readonly JobView[];
|
|
35
|
+
/**
|
|
36
|
+
* Switch a job. **Throw to refuse**, with the reason as the message — the
|
|
37
|
+
* switch goes back where it was and the reason is reported through the
|
|
38
|
+
* `ActionFeedbackProvider`. Without it no switch is drawn.
|
|
39
|
+
*/
|
|
40
|
+
onSwitch?: (jobId: string, on: boolean) => Promise<void>;
|
|
41
|
+
/** Run a job now. Resolve with the route's `message` to have it said; throw to refuse. */
|
|
42
|
+
onRunNow?: (jobId: string) => Promise<{
|
|
43
|
+
message?: string;
|
|
44
|
+
} | void>;
|
|
45
|
+
/** After a switch lands or a run finishes — usually `router.refresh()`. */
|
|
46
|
+
onSettled?: () => void;
|
|
47
|
+
/** Anything of the app's own under a row: AltEd's link to the harvest's screen. */
|
|
48
|
+
extra?: (job: JobView) => React.ReactNode;
|
|
49
|
+
emptyText?: React.ReactNode;
|
|
50
|
+
className?: string;
|
|
51
|
+
classNames?: Partial<JobHealthClassNames>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The health screen's list: each job's schedule, last run, what it did in
|
|
55
|
+
* words, its health, and — for whoever may — its switch and Run now.
|
|
56
|
+
*
|
|
57
|
+
* The switch is an optimistic value: it moves on the click, the badge with it,
|
|
58
|
+
* and a refusal puts both back and says why. AltEd's switch did not move until
|
|
59
|
+
* the server answered, and greyed out every other switch on the screen while it
|
|
60
|
+
* waited.
|
|
61
|
+
*
|
|
62
|
+
* Draws plain elements on the theme tokens, like the wizard; there is still no
|
|
63
|
+
* `Button` in this package. The app wraps it in its own card and heading.
|
|
64
|
+
*/
|
|
65
|
+
export declare function JobHealthList({ jobs, onSwitch, onRunNow, onSettled, extra, emptyText, className, classNames, locale, timeZone, }: JobHealthListProps): React.JSX.Element;
|
|
66
|
+
//# sourceMappingURL=job-health-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-health-list.d.ts","sourceRoot":"","sources":["../../src/jobs/job-health-list.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAErB,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kDAAkD;AAClD,eAAO,MAAM,sBAAsB,EAAE,mBA2BpC,CAAC;AAWF,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,sDAAsD;IACtD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACnE,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,mFAAmF;IACnF,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1C,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,EACL,SAAgC,EAChC,SAAS,EACT,UAAU,EACV,MAAM,EACN,QAAQ,GACT,EAAE,kBAAkB,qBAqBpB"}
|