@codeyam-editor/codeyam-editor 0.1.0-staging.g83619a4 → 0.1.0-staging.gbaebe71
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/npm/cloud.js +27 -1
- package/npm/fleet-add-failure.js +43 -2
- package/npm/fleet-destroy-safety.js +48 -0
- package/npm/fleet-prewarm.js +54 -0
- package/npm/ingress-invoke.js +18 -0
- package/package.json +5 -5
- package/ui/dist/assets/{ContainerInspector-Di2c_yrg.js → ContainerInspector-qJy9NyEZ.js} +1 -1
- package/ui/dist/assets/{EditorShell-BBjfN0wn.js → EditorShell-BM92Hqc1.js} +59 -59
- package/ui/dist/assets/ProjectLauncherScreen-BLHSXp_H.js +1 -0
- package/ui/dist/assets/{ScenarioDataPanel-BlYKgvU_.js → ScenarioDataPanel-BbkUcHum.js} +4 -4
- package/ui/dist/assets/{ScenarioDataPanelFullPage-6-39HCFL.js → ScenarioDataPanelFullPage-CrNwRIZM.js} +1 -1
- package/ui/dist/assets/ScenarioRenderer-mB7opGvg.js +21 -0
- package/ui/dist/assets/index-BygCiJSb.css +1 -0
- package/ui/dist/assets/{index-3Jd_sXhk.js → index-Mui6rJUD.js} +2 -2
- package/ui/dist/assets/useServerIdentity-COXGxKUT.js +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/open-source/codeyam-counter.png +0 -0
- package/ui/dist/open-source/el-carot.png +0 -0
- package/ui/dist/open-source/tabcommand.png +0 -0
- package/ui/dist/assets/ProjectLauncherScreen-C5jktR8F.js +0 -1
- package/ui/dist/assets/ScenarioRenderer-sh_-nNw8.js +0 -21
- package/ui/dist/assets/index-U81w-IPK.css +0 -1
package/npm/cloud.js
CHANGED
|
@@ -965,11 +965,25 @@ function buildGcloudArgs(verb, cfg = {}, extras = {}) {
|
|
|
965
965
|
// real use. Unit tests pin their exports so a refactor cannot drop them.
|
|
966
966
|
// =============================================================================
|
|
967
967
|
|
|
968
|
+
// Per-call wall-clock budget for a single gcloud / SSH invocation. A hung
|
|
969
|
+
// `gcloud describe` (metadata / IAP hiccup) used to block the whole
|
|
970
|
+
// `cloud:reconcile-ingress` sweep forever — the only timeout in the reconcile
|
|
971
|
+
// path was the outer 10-minute exec budget in the dashboard, and that never
|
|
972
|
+
// cascaded to the orphaned descendants. Bounding every per-call spawn well under
|
|
973
|
+
// that outer budget means a single hang trips HERE first: the call returns a
|
|
974
|
+
// timed-out result (formatGcloudFailure renders it), the sweep skips that VM,
|
|
975
|
+
// and no descendant is left hanging to pile up. Shared by runGcloud and the two
|
|
976
|
+
// reconcile spawnSync sites (status probe, per-BES timeout converge) so all three
|
|
977
|
+
// reference one value. 2 min is generous for any single describe/update/SSH probe
|
|
978
|
+
// yet comfortably under the 600000 ms outer reconcile budget.
|
|
979
|
+
const GCLOUD_CALL_TIMEOUT_MS = 120000;
|
|
980
|
+
|
|
968
981
|
function runGcloud(args, opts = {}) {
|
|
969
982
|
return spawnSync("gcloud", args, {
|
|
970
983
|
stdio: opts.stdio || "inherit",
|
|
971
984
|
input: opts.input,
|
|
972
985
|
encoding: opts.encoding || "utf8",
|
|
986
|
+
timeout: opts.timeout != null ? opts.timeout : GCLOUD_CALL_TIMEOUT_MS,
|
|
973
987
|
});
|
|
974
988
|
}
|
|
975
989
|
|
|
@@ -4040,9 +4054,15 @@ async function cmdReconcileIngress(args, projectDir = rootDir) {
|
|
|
4040
4054
|
zone: cfg.zone,
|
|
4041
4055
|
slug,
|
|
4042
4056
|
});
|
|
4057
|
+
// Bound the per-VM status probe: a hung `bash vm-ingress.sh <N> status`
|
|
4058
|
+
// (its gcloud describes stalling on an IAP/metadata hiccup) must not stall the
|
|
4059
|
+
// whole sweep. On timeout res.stdout is empty, so parseIngressStatusVerdict
|
|
4060
|
+
// returns null → an `unknown` verdict → selectIngressReconcileTargets SKIPS
|
|
4061
|
+
// this VM and the sweep continues to the next one.
|
|
4043
4062
|
const res = spawnSync(inv.command, inv.args, {
|
|
4044
4063
|
env: { ...process.env, ...inv.env },
|
|
4045
4064
|
encoding: "utf8",
|
|
4065
|
+
timeout: GCLOUD_CALL_TIMEOUT_MS,
|
|
4046
4066
|
});
|
|
4047
4067
|
return { vmNumber: n, slug, verdict: parseIngressStatusVerdict(res.stdout || "") };
|
|
4048
4068
|
});
|
|
@@ -4097,7 +4117,13 @@ async function cmdReconcileIngress(args, projectDir = rootDir) {
|
|
|
4097
4117
|
for (const surface of gi.SURFACES) {
|
|
4098
4118
|
const bes = gi.backendServiceName(n, surface);
|
|
4099
4119
|
const inv = backendServiceTimeoutInvocation({ bes, project: cfg.project });
|
|
4100
|
-
|
|
4120
|
+
// Bound the per-BES converge too: a hung `gcloud backend-services update`
|
|
4121
|
+
// returns a non-zero (timed-out) result, so it falls into the skip branch
|
|
4122
|
+
// below and the sweep moves on to the next BES rather than stalling.
|
|
4123
|
+
const res = spawnSync(inv.command, inv.args, {
|
|
4124
|
+
encoding: "utf8",
|
|
4125
|
+
timeout: GCLOUD_CALL_TIMEOUT_MS,
|
|
4126
|
+
});
|
|
4101
4127
|
if (res.status === 0) {
|
|
4102
4128
|
console.error(` ${bes}: timeout → 86400`);
|
|
4103
4129
|
} else {
|
package/npm/fleet-add-failure.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fc = require('./fleet-cleanup');
|
|
4
|
+
const { parseRosterMarkers } = require('./fleet-early-roster');
|
|
4
5
|
|
|
5
6
|
// npm/fleet-add-failure.js — pure classifier for a FAILED fleet-dashboard `add`
|
|
6
7
|
// provision. Before this, every failed add rendered an identical red "add error"
|
|
@@ -60,6 +61,16 @@ function lastNonEmptyLines(text, maxLines = 50) {
|
|
|
60
61
|
return lines.join('\n');
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
// True iff the provision transcript reached the early-roster marker (`CY_ROSTER
|
|
65
|
+
// <n>`) — i.e. the instance exists and the container gate passed, so the VM is
|
|
66
|
+
// rostered. Reuses parseRosterMarkers (npm/fleet-early-roster.js) so the
|
|
67
|
+
// `CY_ROSTER` grammar has a single owner rather than a second inlined regex. Any
|
|
68
|
+
// valid marker means "rostered"; the specific VM number is irrelevant here — a
|
|
69
|
+
// provision transcript only ever carries its own VM's marker. Never throws.
|
|
70
|
+
function transcriptRostered(logTail) {
|
|
71
|
+
return parseRosterMarkers(String(logTail || '')).length > 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
63
74
|
// Build a verdict, stamping `retryable` from the single-source-of-truth Set so it
|
|
64
75
|
// can never drift from the category.
|
|
65
76
|
function buildFailureVerdict(category, headline, recovery, extra) {
|
|
@@ -144,7 +155,25 @@ function classifyAddFailure({ logTail, exitCode } = {}) {
|
|
|
144
155
|
'The provision was interrupted (killed or out of memory), so the VM state is unknown. Reconcile or destroy this VM before re-adding.');
|
|
145
156
|
}
|
|
146
157
|
|
|
147
|
-
// 7.
|
|
158
|
+
// 7. converging — the add reached the early-roster marker (`CY_ROSTER`): the
|
|
159
|
+
// container gate passed, the instance is real, and the VM is rostered, yet it
|
|
160
|
+
// exited non-zero WITHOUT matching any specific hard-failure signature above.
|
|
161
|
+
// By construction of the provision script, every genuine hard failure (drift,
|
|
162
|
+
// instance-vanished, container-stuck, incomplete-workspace, cloud-up-failed,
|
|
163
|
+
// interrupted) is printed BEFORE `CY_ROSTER`, so a rostered transcript that
|
|
164
|
+
// fell through to here is a still-wiring box owned by the detached
|
|
165
|
+
// wire-add-tail / reconcile-ingress — NOT an add failure. Surface it as an
|
|
166
|
+
// honest in-flight state instead of the scary red `unknown`. Not retryable:
|
|
167
|
+
// the VM exists and its detached wiring owns finishing it, so a one-click
|
|
168
|
+
// retry could duplicate/orphan a live box. Tested LAST so a hard-failure
|
|
169
|
+
// signature (all printed pre-roster) always wins — `converging` can never
|
|
170
|
+
// shadow a proven failure.
|
|
171
|
+
if (transcriptRostered(log)) {
|
|
172
|
+
return buildFailureVerdict('converging', 'Add still converging',
|
|
173
|
+
'The container is up and the VM is rostered; the LB ingress is still wiring in the background. This resolves on its own once the editor is reachable over the LB — no action needed unless it persists past the wiring deadline.');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 8. unknown — fallback. Never invite an unproven retry.
|
|
148
177
|
return buildFailureVerdict('unknown', 'Add failed',
|
|
149
178
|
'The add failed for an unclassified reason — inspect the transcript below, then reconcile or destroy this VM before re-adding.');
|
|
150
179
|
}
|
|
@@ -163,4 +192,16 @@ function canRetryAdd({ n, job } = {}) {
|
|
|
163
192
|
return { ok: true, reason: null };
|
|
164
193
|
}
|
|
165
194
|
|
|
166
|
-
|
|
195
|
+
// Pure badge-hold predicate for deriveStatus (server.js): hold the calm in-flight
|
|
196
|
+
// `add-converging` card — instead of the red add-failed — ONLY when the add was
|
|
197
|
+
// classified `converging` AND its detached first-wiring is still in flight. Once
|
|
198
|
+
// the wire-add-tail fails/deadlines (`addTailFailed`) or is gone (`addTailInflight`
|
|
199
|
+
// false), or the category is anything else, return false so the caller falls
|
|
200
|
+
// through to the red add-failed status — the operator-chosen escalation. Kept pure
|
|
201
|
+
// (like canRetryAdd / canClearBadge) so the badge decision is unit-tested without a
|
|
202
|
+
// live dashboard.
|
|
203
|
+
function holdConvergingBadge({ category, addTailInflight, addTailFailed } = {}) {
|
|
204
|
+
return category === 'converging' && !!addTailInflight && !addTailFailed;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports = { classifyAddFailure, extractDriftFiles, lastNonEmptyLines, canRetryAdd, transcriptRostered, holdConvergingBadge, ADD_FAILURE_RETRYABLE };
|
|
@@ -32,6 +32,40 @@ function classifyDestroyBlock({ authDegraded, fleetWide } = {}) {
|
|
|
32
32
|
return { blocked: false, reason: null };
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// Classify a non-Force destroy's unpushed-commit INTENT decision from the WARM
|
|
36
|
+
// ahead-count the dashboard reads off /api/session-info, mirroring the pure
|
|
37
|
+
// decision shape of classifyDestroyBlock. The three outcomes:
|
|
38
|
+
// ahead number > 0 → REFUSE: unpushed work exists (Force-recoverable)
|
|
39
|
+
// ahead number === 0 → PROCEED: verified clean
|
|
40
|
+
// ahead null / undefined → REFUSE: could NOT verify (editor unreachable /
|
|
41
|
+
// field absent) — a DISTINCT refusal, never conflated
|
|
42
|
+
// with "VM down", and Force-recoverable
|
|
43
|
+
// Returns { refuse, forceable, outcome, msg }: `outcome` is the
|
|
44
|
+
// logDestroyDecision attribution token (null when proceeding); `msg` is the
|
|
45
|
+
// operator-facing refusal text (null when proceeding). Pure — the caller owns the
|
|
46
|
+
// warm probe, the cached fallback, the logging, and the return; this only maps
|
|
47
|
+
// ahead → decision so it is unit-testable in isolation (the way the cold-SSH
|
|
48
|
+
// version never was).
|
|
49
|
+
function classifyUnpushedDestroy({ n, ahead } = {}) {
|
|
50
|
+
if (typeof ahead === 'number' && ahead > 0) {
|
|
51
|
+
return {
|
|
52
|
+
refuse: true,
|
|
53
|
+
forceable: true,
|
|
54
|
+
outcome: 'REFUSED:unpushed',
|
|
55
|
+
msg: `VM-${n} has ${ahead} unpushed commit(s) — not destroying. Use Force to override.`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (ahead === 0) {
|
|
59
|
+
return { refuse: false, forceable: false, outcome: null, msg: null };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
refuse: true,
|
|
63
|
+
forceable: true,
|
|
64
|
+
outcome: 'REFUSED:unverifiable',
|
|
65
|
+
msg: `VM-${n} — could not verify unpushed commits (editor unreachable). Use Force to destroy anyway.`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
35
69
|
// Build the single attributable destroy-decision log line. Mirrors the
|
|
36
70
|
// performAutoReset "confirmed … not fleet-wide" template so every destroy —
|
|
37
71
|
// proceed OR refused, across every trigger source — is diagnosable from one
|
|
@@ -49,7 +83,21 @@ function formatDestroyDecision(info = {}) {
|
|
|
49
83
|
);
|
|
50
84
|
}
|
|
51
85
|
|
|
86
|
+
// Build the single TERMINAL-OUTCOME journal line for a completed destroy JOB —
|
|
87
|
+
// the sibling of formatDestroyDecision, which records the up-front DECISION. The
|
|
88
|
+
// decision line alone was a blind spot: diagnosing the VM-8 silent refusal
|
|
89
|
+
// surfaced only `destroy-decision … → proceed:delete`, nothing about how the job
|
|
90
|
+
// itself ended, so a job that refused/errored after the decision was invisible.
|
|
91
|
+
// With this line a completed destroy's fate is one `grep destroy-outcome` away.
|
|
92
|
+
// `outcome` is the caller-computed terminal string: `done`, `refused:<kind>`, or
|
|
93
|
+
// `error code=<n>`. Pure format only — the caller owns the classification.
|
|
94
|
+
function formatDestroyOutcome(info = {}) {
|
|
95
|
+
return `destroy-outcome: VM-${info.n} ${info.outcome}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
52
98
|
module.exports = {
|
|
53
99
|
classifyDestroyBlock,
|
|
100
|
+
classifyUnpushedDestroy,
|
|
54
101
|
formatDestroyDecision,
|
|
102
|
+
formatDestroyOutcome,
|
|
55
103
|
};
|
package/npm/fleet-prewarm.js
CHANGED
|
@@ -25,6 +25,14 @@ const MARKER_PUBLISH_SKIPPED = 'CY_BINARY_PUBLISH_SKIPPED'; // pacer will NOT pu
|
|
|
25
25
|
const MARKER_PATH_PULL = 'CY_PROVISION_PATH pull'; // this VM pulled a prebuilt image (~2 min fast path)
|
|
26
26
|
const MARKER_PATH_COMPILE = 'CY_PROVISION_PATH compile'; // this VM compiled from source (~10 min slow path)
|
|
27
27
|
|
|
28
|
+
// Markers scripts/cloud-refresh-binary.sh emits into the between-session
|
|
29
|
+
// refresh log (/tmp/dash-refresh-binary-vm-<n>.log, or the systemd journal when
|
|
30
|
+
// the timer runs it unattended). Same stable-contract rule as the four above.
|
|
31
|
+
const MARKER_REFRESHED = 'CY_BINARY_REFRESHED'; // pulled + swapped a newer published binary, container restarted
|
|
32
|
+
const MARKER_REFRESH_CURRENT = 'CY_BINARY_CURRENT'; // already on the newest published binary; nothing to do
|
|
33
|
+
const MARKER_REFRESH_DEFERRED = 'CY_BINARY_REFRESH_DEFERRED'; // newer binary exists but a session is live (or state unknown)
|
|
34
|
+
const MARKER_REFRESH_DEGRADED = 'CY_DEGRADED binary-refresh'; // the refresh could NOT complete — this VM may be running stale
|
|
35
|
+
|
|
28
36
|
// Mirror scripts/gcp-bootstrap.sh's BRANCH_SLUG: '/' → '-', lowercased, capped
|
|
29
37
|
// at 128 chars. The dashboard and the VM MUST agree on the slug or the probe
|
|
30
38
|
// checks different tags than the bootstrap pulls. Empty / missing branch → the
|
|
@@ -171,11 +179,57 @@ function pushTokenDiagnostic({ hasPushToken } = {}) {
|
|
|
171
179
|
};
|
|
172
180
|
}
|
|
173
181
|
|
|
182
|
+
// What did the last between-session binary refresh do? Parsed from the refresh
|
|
183
|
+
// log for the VM card, so an operator can tell "up to date" from "could not
|
|
184
|
+
// update" without opening a log.
|
|
185
|
+
//
|
|
186
|
+
// Returns 'refreshed' | 'current' | 'deferred' | 'degraded' | null (no refresh
|
|
187
|
+
// has reported yet).
|
|
188
|
+
//
|
|
189
|
+
// The LAST marker wins, for the same reason provisionPath() takes the last one:
|
|
190
|
+
// a tick that defers and a later tick that refreshes must read as refreshed,
|
|
191
|
+
// not stay stuck on the older verdict. Ordering — not precedence between marker
|
|
192
|
+
// kinds — is what makes this correct across repeated timer runs.
|
|
193
|
+
//
|
|
194
|
+
// `degraded` is deliberately a distinct state from `deferred`. Deferring is the
|
|
195
|
+
// mechanism working as designed (a session is live, so we wait). Degraded means
|
|
196
|
+
// the VM wanted a newer binary and could NOT get one — the silent-staleness
|
|
197
|
+
// case this whole mechanism exists to make visible, and the only one that
|
|
198
|
+
// warrants an operator's attention.
|
|
199
|
+
function binaryRefreshState(logText) {
|
|
200
|
+
if (!logText || typeof logText !== 'string') return null;
|
|
201
|
+
const at = (marker) => logText.lastIndexOf(marker);
|
|
202
|
+
const candidates = [
|
|
203
|
+
['refreshed', at(MARKER_REFRESHED)],
|
|
204
|
+
['current', at(MARKER_REFRESH_CURRENT)],
|
|
205
|
+
['deferred', at(MARKER_REFRESH_DEFERRED)],
|
|
206
|
+
['degraded', at(MARKER_REFRESH_DEGRADED)],
|
|
207
|
+
].filter(([, idx]) => idx >= 0);
|
|
208
|
+
if (!candidates.length) return null;
|
|
209
|
+
return candidates.reduce((best, cur) => (cur[1] > best[1] ? cur : best))[0];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Operator-facing one-liner for a refresh state, for the VM card. null state →
|
|
213
|
+
// null (render nothing — a VM that has never run a refresh is not a problem).
|
|
214
|
+
function binaryRefreshLabel(state) {
|
|
215
|
+
if (state === 'refreshed') return 'editor binary refreshed to the newest published build';
|
|
216
|
+
if (state === 'current') return 'editor binary up to date';
|
|
217
|
+
if (state === 'deferred') return 'newer editor binary available — waiting for the session to end';
|
|
218
|
+
if (state === 'degraded') return 'could NOT refresh the editor binary — may be running stale';
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
174
222
|
module.exports = {
|
|
175
223
|
MARKER_PUBLISHED,
|
|
176
224
|
MARKER_PUBLISH_SKIPPED,
|
|
177
225
|
MARKER_PATH_PULL,
|
|
178
226
|
MARKER_PATH_COMPILE,
|
|
227
|
+
MARKER_REFRESHED,
|
|
228
|
+
MARKER_REFRESH_CURRENT,
|
|
229
|
+
MARKER_REFRESH_DEFERRED,
|
|
230
|
+
MARKER_REFRESH_DEGRADED,
|
|
231
|
+
binaryRefreshState,
|
|
232
|
+
binaryRefreshLabel,
|
|
179
233
|
branchSlug,
|
|
180
234
|
usableImageTags,
|
|
181
235
|
decideBatchPrewarm,
|
package/npm/ingress-invoke.js
CHANGED
|
@@ -224,6 +224,23 @@ function selectIngressGrantOnlyTargets(statuses) {
|
|
|
224
224
|
return statuses.filter((s) => s && s.verdict === 'wired');
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
/** Compute the `process.kill` target that reaps a timed-out reconcile's ENTIRE
|
|
228
|
+
* process group. The dashboard spawns `cloud:reconcile-ingress` detached, so the
|
|
229
|
+
* child shell leads its own process group (pgid === child.pid) and a negative-pid
|
|
230
|
+
* signal reaps every descendant — `node cloud.js` → `bash vm-ingress.sh` →
|
|
231
|
+
* `gcloud` — instead of only the immediate `sh -c` child (what an exec/SIGTERM
|
|
232
|
+
* timeout does, orphaning the descendants to init where they pile up and wedge the
|
|
233
|
+
* dashboard). Returns `-pid` for a real detached child, or `null` when the pid is
|
|
234
|
+
* missing / already reaped or would be catastrophic to negate. The `> 1` guard is
|
|
235
|
+
* load-bearing: `process.kill(-1, …)` signals EVERY process the user owns and
|
|
236
|
+
* `process.kill(0, …)`/`-0` targets the caller's OWN group — a missing pid must
|
|
237
|
+
* never be turned into a fleet-wide or self-directed SIGKILL. Pure: pid in, target
|
|
238
|
+
* out, so the timeout-kill decision is unit-testable without spawning a process. */
|
|
239
|
+
function reconcileGroupKillTarget(childPid) {
|
|
240
|
+
if (!Number.isInteger(childPid) || childPid <= 1) return null;
|
|
241
|
+
return -childPid;
|
|
242
|
+
}
|
|
243
|
+
|
|
227
244
|
/** Pick the genuine orphans from the VM numbers that currently HAVE LB ingress
|
|
228
245
|
* resources (`ingressVmNumbers`, derived from the live backend-service AND NEG
|
|
229
246
|
* names). A number is an orphan iff it has ingress but is NOT in the roster,
|
|
@@ -685,6 +702,7 @@ module.exports = {
|
|
|
685
702
|
parseIngressTeardownVerdict,
|
|
686
703
|
selectIngressReconcileTargets,
|
|
687
704
|
selectIngressGrantOnlyTargets,
|
|
705
|
+
reconcileGroupKillTarget,
|
|
688
706
|
selectOrphanIngressTargets,
|
|
689
707
|
classifyOrphanDownResult,
|
|
690
708
|
parseOrphanSweepSummary,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeyam-editor/codeyam-editor",
|
|
3
|
-
"version": "0.1.0-staging.
|
|
3
|
+
"version": "0.1.0-staging.gbaebe71",
|
|
4
4
|
"description": "Language-agnostic managed execution sandbox for scenario-driven development",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codeyam-editor": "./npm/cli.js"
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"playwright": "^1.58.2"
|
|
10
10
|
},
|
|
11
11
|
"optionalDependencies": {
|
|
12
|
-
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.0-staging.
|
|
13
|
-
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.0-staging.
|
|
14
|
-
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.0-staging.
|
|
15
|
-
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.0-staging.
|
|
12
|
+
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.0-staging.gbaebe71",
|
|
13
|
+
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.0-staging.gbaebe71",
|
|
14
|
+
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.0-staging.gbaebe71",
|
|
15
|
+
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.0-staging.gbaebe71"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"codeyam",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./markdown-C9tbsVHX.js";import{b as a}from"./react-nrLBr15I.js";import{u as O}from"./useEvents-S3Qk1Y_d.js";import{b as E}from"./index-
|
|
1
|
+
import{j as e}from"./markdown-C9tbsVHX.js";import{b as a}from"./react-nrLBr15I.js";import{u as O}from"./useEvents-S3Qk1Y_d.js";import{b as E}from"./index-Mui6rJUD.js";function P({connected:t}){return e.jsx("span",{className:`inline-block rounded-full px-2 py-0.5 text-xs font-medium text-[var(--text-primary)] ${t?"bg-[var(--accent-green)]":"bg-[var(--accent-red)]"}`,children:t?"connected":"reconnecting…"})}const re=Object.freeze(Object.defineProperty({__proto__:null,ConnectionBadge:P},Symbol.toStringTag,{value:"Module"}));function N(){const[t,r]=a.useState(null),[o,s]=a.useState(!0),{events:l}=O(),n=a.useCallback(async()=>{try{const c=await(await fetch("/api/inspector/status")).json();r(c)}catch{}finally{s(!1)}},[]);return a.useEffect(()=>{n()},[n]),a.useEffect(()=>{const i=l[l.length-1];i&&i.type==="scenario_switch"&&n()},[l,n]),{scenario:(t==null?void 0:t.scenario)??null,previewScenario:(t==null?void 0:t.previewScenario)??null,routes:(t==null?void 0:t.routes)??[],routeCount:(t==null?void 0:t.routeCount)??0,loading:o,refetch:n}}function v({title:t}){return e.jsx("h2",{style:{fontSize:14,fontWeight:600,color:"#f0f6fc",margin:"0 0 8px 0",borderBottom:"1px solid #30363d",paddingBottom:8},children:t})}function f({color:t,children:r}){return e.jsx("span",{style:{background:`${t}22`,color:t,border:`1px solid ${t}55`,borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,letterSpacing:"0.5px",whiteSpace:"nowrap"},children:r})}const $={GET:"#D7FF63",POST:"#238636",PUT:"#d29922",DELETE:"#da3633",PATCH:"#bc8cff"};function k({method:t}){const r=$[t.toUpperCase()]??"#8b949e";return e.jsx("span",{style:{color:r,fontWeight:600,fontSize:11,minWidth:48,display:"inline-block"},children:t.toUpperCase()})}function C({color:t,children:r}){return e.jsx("div",{style:{padding:"12px 16px",borderRadius:6,border:`1px solid ${t}44`,background:`${t}11`,color:t},children:r})}const u={padding:"8px 12px",textAlign:"center",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},h={padding:"6px 12px"},S={background:"#161b22",border:"1px solid #30363d",borderRadius:6,color:"#c9d1d9",padding:"6px 12px",fontSize:13,fontFamily:"inherit"},R={...S,appearance:"none",paddingRight:24,backgroundImage:`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%238b949e' d='M6 8L1 3h10z'/%3E%3C/svg%3E")`,backgroundRepeat:"no-repeat",backgroundPosition:"right 8px center"},oe=Object.freeze(Object.defineProperty({__proto__:null,Badge:f,MethodBadge:k,SectionHeader:v,StatusBox:C,inputStyle:S,selectStyle:R,tdStyle:h,thStyle:u},Symbol.toStringTag,{value:"Module"}));function z({routes:t}){return e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d"},children:[e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"Pattern"}),e.jsx("th",{style:u,children:"Status"})]})}),e.jsx("tbody",{children:t.map((r,o)=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:r.method})}),e.jsx("td",{style:h,children:r.pattern}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:r.status})]},o))})]})}const se=Object.freeze(Object.defineProperty({__proto__:null,InspectorRouteTable:z},Symbol.toStringTag,{value:"Module"}));function A(){const{scenario:t,previewScenario:r,routes:o,routeCount:s,loading:l}=N();return e.jsxs("section",{children:[e.jsx(v,{title:"Active Scenario"}),l?e.jsx(C,{color:"#8b949e",children:"Loading..."}):t?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#238636",children:"ACTIVE"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:t.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",t.slug,")"]})]}),e.jsxs("div",{style:{color:"#8b949e",fontSize:12},children:[s," mock route",s!==1?"s":""," loaded"]}),o.length>0&&e.jsx(z,{routes:o})]}):r?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(f,{color:"#D7FF63",children:"PREVIEW"}),e.jsx("span",{style:{color:"#f0f6fc",fontWeight:500},children:r.name}),e.jsxs("span",{style:{color:"#8b949e"},children:["(",r.slug,")"]})]}),e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"Component preview — no HTTP mocks active"})]}):e.jsx(C,{color:"#d29922",children:"No scenario active — all requests pass through to upstream"})]})}const ne=Object.freeze(Object.defineProperty({__proto__:null,InspectorScenarioSection:A},Symbol.toStringTag,{value:"Module"}));function F({textUrlFilter:t,onTextUrlFilterChange:r,methodFilter:o,onMethodFilterChange:s,sourceFilter:l,onSourceFilterChange:n}){return e.jsxs("div",{style:{display:"flex",gap:8,marginBottom:12,alignItems:"center"},children:[e.jsx("input",{type:"text",placeholder:"Filter by URL...",value:t,onChange:i=>r(i.target.value),style:{...S,flex:1,minWidth:0}}),e.jsxs("select",{value:o,onChange:i=>s(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Methods"}),e.jsx("option",{value:"GET",children:"GET"}),e.jsx("option",{value:"POST",children:"POST"}),e.jsx("option",{value:"PUT",children:"PUT"}),e.jsx("option",{value:"DELETE",children:"DELETE"}),e.jsx("option",{value:"PATCH",children:"PATCH"})]}),e.jsxs("select",{value:l,onChange:i=>n(i.target.value),style:R,children:[e.jsx("option",{value:"ALL",children:"All Sources"}),e.jsx("option",{value:"MOCKED",children:"Mocked"}),e.jsx("option",{value:"PASSTHROUGH",children:"Passthrough"})]})]})}const ie=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficFilterBar:F},Symbol.toStringTag,{value:"Module"})),G={color:"#8b949e",fontSize:11,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:4},M={background:"#161b22",border:"1px solid #30363d",borderRadius:4,padding:"8px 12px",margin:0,fontSize:11,color:"#c9d1d9",fontFamily:"monospace",maxHeight:200,overflow:"auto",whiteSpace:"pre-wrap",wordBreak:"break-all"};function _({label:t,children:r}){return e.jsxs("div",{style:{marginBottom:12},children:[e.jsx("div",{style:G,children:t}),r]})}function B({event:t}){let r=[];try{const n=new URL(t.url,"http://localhost");r=Array.from(n.searchParams.entries())}catch{}const o=t.requestHeaders&&Object.keys(t.requestHeaders).length>0,s=t.requestBody!=null,l=t.responseBody!=null;return e.jsxs("div",{style:{background:"#0d1117",padding:"12px 16px",borderTop:"1px solid #30363d"},children:[r.length>0&&e.jsx(_,{label:"Query Parameters",children:e.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"2px 12px",fontSize:12},children:r.map(([n,i],c)=>e.jsxs("div",{style:{display:"contents"},children:[e.jsx("span",{style:{color:"#D7FF63",fontFamily:"monospace"},children:n}),e.jsx("span",{style:{color:"#c9d1d9",fontFamily:"monospace"},children:i})]},c))})}),o&&e.jsx(_,{label:"Request Headers",children:e.jsx("pre",{style:M,children:Object.entries(t.requestHeaders).map(([n,i])=>`${n}: ${i}`).join(`
|
|
2
2
|
`)})}),s&&e.jsx(_,{label:"Request Body",children:e.jsx("pre",{style:M,children:typeof t.requestBody=="string"?t.requestBody:JSON.stringify(t.requestBody,null,2)})}),l&&e.jsx(_,{label:"Response Body",children:e.jsx("pre",{style:M,children:typeof t.responseBody=="string"?t.responseBody:JSON.stringify(t.responseBody,null,2)})}),r.length===0&&!o&&!s&&!l&&e.jsx("div",{style:{color:"#8b949e",fontSize:12},children:"No additional details available for this request"})]})}const le=Object.freeze(Object.defineProperty({__proto__:null,DetailSection:_,InspectorTrafficDetail:B},Symbol.toStringTag,{value:"Module"}));function L({event:t}){const[r,o]=a.useState(!1),s=new Date(t.timestampMs).toLocaleTimeString(),l=t.mocked;return e.jsxs(e.Fragment,{children:[e.jsxs("tr",{onClick:()=>o(!r),style:{borderBottom:"1px solid #21262d",background:l?"transparent":"rgba(210, 153, 34, 0.05)",cursor:"pointer"},children:[e.jsxs("td",{style:{...h,color:"#8b949e",textAlign:"center"},children:[e.jsx("span",{style:{display:"inline-block",width:12,marginRight:4,fontSize:10,color:"#8b949e",transition:"transform 0.15s",transform:r?"rotate(90deg)":"rotate(0deg)"},children:"▶"}),s]}),e.jsx("td",{style:{...h,textAlign:"center"},children:e.jsx(k,{method:t.method})}),e.jsx("td",{style:{...h,maxWidth:400,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.url}),e.jsx("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:t.status??"---"}),e.jsxs("td",{style:{...h,textAlign:"center",color:"#8b949e"},children:[t.durationMs,"ms"]}),e.jsx("td",{style:{...h,textAlign:"center"},children:l?t.mockSource==="default"?e.jsx(f,{color:"#1f6feb",children:"MOCKED (default)"}):e.jsx(f,{color:"#238636",children:"MOCKED (scenario)"}):e.jsx(f,{color:"#d29922",children:"PASSTHROUGH"})})]}),r&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,style:{padding:0},children:e.jsx(B,{event:t})})})]})}const ae=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficRow:L},Symbol.toStringTag,{value:"Module"}));function D({events:t}){return e.jsx("div",{style:{maxHeight:300,overflowY:"auto",border:"1px solid #30363d",borderRadius:6},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",position:"sticky",top:0,background:"#0d1117"},children:[e.jsx("th",{style:u,children:"Time"}),e.jsx("th",{style:u,children:"Method"}),e.jsx("th",{style:{...u,textAlign:"left"},children:"URL"}),e.jsx("th",{style:u,children:"Status"}),e.jsx("th",{style:u,children:"Duration"}),e.jsx("th",{style:u,children:"Source"})]})}),e.jsx("tbody",{children:t.map(r=>e.jsx(L,{event:r},r.id))})]})})}const ce=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficTable:D},Symbol.toStringTag,{value:"Module"}));function K(t){if(t===void 0)return"checked";if(t==="checked")return"excluded"}function I({chips:t,chipStates:r,onChipStatesChange:o}){if(t.length===0)return null;const s=n=>{const i=new Map(r),c=K(i.get(n));c===void 0?i.delete(n):i.set(n,c),o(i)},l=()=>{o(new Map)};return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,marginBottom:12},children:[r.size>0&&e.jsx("button",{onClick:l,style:{background:"#da363322",color:"#da3633",border:"1px solid #da363355",borderRadius:4,padding:"2px 8px",fontSize:11,fontWeight:600,cursor:"pointer",fontFamily:"inherit"},children:"Clear all"}),t.map(({path:n,count:i})=>{const c=r.get(n),d=c==="checked",g=c==="excluded";let m="#30363d",b="#8b949e",T="#30363d",y="";return d?(m="#D7FF6322",b="#D7FF63",T="#D7FF6355",y="✓ "):g&&(m="#da363322",b="#da3633",T="#da363355",y="✗ "),e.jsxs("button",{onClick:()=>s(n),style:{background:m,color:b,border:`1px solid ${T}`,borderRadius:4,padding:"2px 8px",fontSize:11,fontFamily:"monospace",cursor:"pointer",whiteSpace:"nowrap"},children:[y,n,e.jsxs("span",{style:{marginLeft:4,opacity:.6,fontFamily:"inherit"},children:["(",i,")"]})]},n)})]})}const de=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficUrlChips:I},Symbol.toStringTag,{value:"Module"}));function H(){const{events:t}=O(),[r,o]=a.useState(""),[s,l]=a.useState(()=>new Map),[n,i]=a.useState("ALL"),[c,d]=a.useState("ALL"),g=t.filter(p=>p.type==="http_request"),m=a.useMemo(()=>{const p=new Map;for(const x of g){const j=E(x.url);p.set(j,(p.get(j)||0)+1)}return Array.from(p.entries()).sort((x,j)=>j[1]-x[1]).slice(0,10).map(([x,j])=>({path:x,count:j}))},[g]),b=a.useMemo(()=>Array.from(s.values()).some(p=>p==="checked"),[s]),y=g.filter(p=>{if(r&&!p.url.toLowerCase().includes(r.toLowerCase()))return!1;const x=E(p.url);return!(s.get(x)==="excluded"||b&&s.get(x)!=="checked"||n!=="ALL"&&p.method.toUpperCase()!==n||c==="MOCKED"&&!p.mocked||c==="PASSTHROUGH"&&p.mocked)}).slice(-50).reverse();return e.jsxs("section",{children:[e.jsx(v,{title:"Live Traffic"}),e.jsx(F,{textUrlFilter:r,onTextUrlFilterChange:o,methodFilter:n,onMethodFilterChange:i,sourceFilter:c,onSourceFilterChange:p=>d(p)}),e.jsx(I,{chips:m,chipStates:s,onChipStatesChange:l}),y.length===0?e.jsx(C,{color:"#8b949e",children:g.length>0?"No matching traffic — try adjusting the filters":"No HTTP traffic yet — requests will appear here in real-time"}):e.jsx(D,{events:y})]})}const pe=Object.freeze(Object.defineProperty({__proto__:null,InspectorTrafficSection:H},Symbol.toStringTag,{value:"Module"}));function J(){const[t,r]=a.useState(null),[o,s]=a.useState(!1);return{explain:a.useCallback(async(n,i)=>{s(!0);try{const d=await(await fetch("/api/inspector/explain",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({method:n,url:i})})).json();r(d)}catch{}finally{s(!1)}},[]),result:t,loading:o}}function U({result:t}){return e.jsxs("div",{style:{border:"1px solid #30363d",borderRadius:6,padding:12},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:12},children:[e.jsxs("span",{style:{color:"#f0f6fc",fontWeight:500},children:[t.method," ",t.url]}),t.wouldMatch?e.jsx(f,{color:"#238636",children:"WOULD MATCH"}):e.jsx(f,{color:"#da3633",children:"NO MATCH"})]}),t.attempts.length===0?e.jsx("div",{style:{color:"#8b949e"},children:"No routes loaded to match against"}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:6},children:t.attempts.map((r,o)=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",borderRadius:4,background:r.failure?"transparent":"rgba(35, 134, 54, 0.1)"},children:[e.jsx("span",{style:{color:r.failure?"#da3633":"#238636",fontWeight:600,width:16},children:r.failure?"x":"v"}),e.jsx(k,{method:r.method}),e.jsx("span",{children:r.pattern}),r.failure&&e.jsx("span",{style:{color:"#8b949e",fontSize:11},children:r.failure.reason==="methodMismatch"?`method: expected ${r.failure.expected}, got ${r.failure.actual}`:`path "${r.failure.path}" does not match "${r.failure.pattern}"`})]},o))})]})}const ue=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerResult:U},Symbol.toStringTag,{value:"Module"}));function W(){const{explain:t,result:r,loading:o}=J(),[s,l]=a.useState("GET"),[n,i]=a.useState(""),c=d=>{d.preventDefault(),n.trim()&&t(s,n.trim())};return e.jsxs("section",{children:[e.jsx(v,{title:"Match Explainer"}),e.jsxs("form",{onSubmit:c,style:{display:"flex",gap:8,marginBottom:12},children:[e.jsx("select",{value:s,onChange:d=>l(d.target.value),style:{...S,width:100},children:["GET","POST","PUT","DELETE","PATCH"].map(d=>e.jsx("option",{value:d,children:d},d))}),e.jsx("input",{type:"text",value:n,onChange:d=>i(d.target.value),placeholder:"/api/users",style:{...S,flex:1}}),e.jsx("button",{type:"submit",disabled:o||!n.trim(),style:{background:"#238636",color:"#fff",border:"none",borderRadius:6,padding:"6px 16px",cursor:"pointer",fontSize:12,fontWeight:500,opacity:o||!n.trim()?.5:1},children:o?"Checking...":"Explain"})]}),r&&e.jsx(U,{result:r})]})}const he=Object.freeze(Object.defineProperty({__proto__:null,InspectorExplainerSection:W},Symbol.toStringTag,{value:"Module"})),w={"/api/health":"Health check — confirms the proxy and mock engine are running","/api/events":"SSE stream of real-time events (traffic, errors) powering this Inspector","/api/config":"Returns current CodeYam configuration for the project","/api/editor-dev-server":"Polls/controls the dev server status (start, stop, restart)","/api/inspector/status":"Returns active scenario and loaded mock routes","/api/inspector/explain":"Tests which mock route would match a given method + URL","/api/scenarios":"Lists all defined scenarios with metadata","/api/tests":"Returns the AI-maintained test registry joined with per-test-evidence, grouped by file","/api/test-results":"Returns latest test execution results","/api/screenshots/*":"Serves captured scenario screenshots","/api/session-info":"Returns current editor session metadata","/api/data-structure":"Returns the app's data structure definition","/api/dependency-graph":"Returns the project's component dependency graph","/api/app-route-entities":"Lists app routes and their associated entities","/api/glossary":"Returns the project's component glossary","/api/step":"Returns current editor workflow step","/api/editor-commands":"Lists available editor commands"};function V(t){if(w[t])return w[t];for(const[r,o]of Object.entries(w))if(r.endsWith("/*")){const s=r.slice(0,-1);if(t.startsWith(s))return o}}function Y(t){const r=new Set([...t,...Object.keys(w)]),o=[];for(const s of Array.from(r).sort()){if(s.endsWith("/*"))continue;const l=V(s);o.push({path:s,description:l??"Application endpoint"})}return o}function q(){const{events:t}=O(),r=a.useMemo(()=>{const o=[];for(const s of t)s.type==="http_request"&&o.push(E(s.url));return Y(o)},[t]);return r.length===0?null:e.jsxs("section",{children:[e.jsx(v,{title:"URL Glossary"}),e.jsx("div",{style:{border:"1px solid #30363d",borderRadius:6,overflow:"hidden"},children:e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:12},children:[e.jsx("thead",{children:e.jsxs("tr",{style:{borderBottom:"1px solid #30363d",background:"#161b22"},children:[e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px",width:"30%"},children:"Path"}),e.jsx("th",{style:{padding:"6px 12px",textAlign:"left",color:"#8b949e",fontWeight:500,fontSize:11,textTransform:"uppercase",letterSpacing:"0.5px"},children:"Description"})]})}),e.jsx("tbody",{children:r.map(({path:o,description:s})=>e.jsxs("tr",{style:{borderBottom:"1px solid #21262d"},children:[e.jsx("td",{style:{padding:"4px 12px",fontFamily:"monospace",color:"#D7FF63",fontSize:11},children:o}),e.jsx("td",{style:{padding:"4px 12px",color:"#8b949e"},children:s})]},o))})]})})]})}const xe=Object.freeze(Object.defineProperty({__proto__:null,InspectorUrlGlossary:q},Symbol.toStringTag,{value:"Module"}));function Q(){const{connected:t}=O();return e.jsxs("div",{style:{background:"#0d1117",color:"#c9d1d9",minHeight:"100vh",fontFamily:"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace",fontSize:13,padding:24,display:"flex",flexDirection:"column",gap:24},children:[e.jsxs("header",{style:{display:"flex",alignItems:"center",gap:12},children:[e.jsx("h1",{style:{fontSize:18,fontWeight:600,color:"#f0f6fc",margin:0},children:"Container Inspector"}),e.jsx("span",{style:{color:"#8b949e",fontSize:12},children:"Read-only view of proxy and mock engine state"}),e.jsx(P,{connected:t})]}),e.jsx(A,{}),e.jsx(H,{}),e.jsx(W,{}),e.jsx(q,{})]})}const fe=Object.freeze(Object.defineProperty({__proto__:null,ContainerInspector:Q},Symbol.toStringTag,{value:"Module"}));export{f as B,Q as C,_ as D,L as I,k as M,v as S,xe as _,C as a,q as b,I as c,D as d,F as e,B as f,U as g,W as h,H as i,z as j,A as k,P as l,de as m,ce as n,pe as o,ae as p,ie as q,le as r,ne as s,u as t,se as u,oe as v,he as w,ue as x,fe as y,re as z};
|