@enricai/barnacle 1.6.10 → 1.6.12
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 +71 -3
- package/dist/api/routes/submissions.d.ts +21 -0
- package/dist/api/routes/submissions.d.ts.map +1 -0
- package/dist/api/routes/submissions.js +48 -0
- package/dist/api/routes/submissions.js.map +1 -0
- package/dist/api/schemas/submissions.d.ts +110 -0
- package/dist/api/schemas/submissions.d.ts.map +1 -0
- package/dist/api/schemas/submissions.js +77 -0
- package/dist/api/schemas/submissions.js.map +1 -0
- package/dist/config.d.ts +34 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/lib/telemetry/beacon-capture.d.ts +37 -0
- package/dist/lib/telemetry/beacon-capture.d.ts.map +1 -0
- package/dist/lib/telemetry/beacon-capture.js +47 -0
- package/dist/lib/telemetry/beacon-capture.js.map +1 -0
- package/dist/lib/telemetry/reconciliation-record.d.ts +113 -0
- package/dist/lib/telemetry/reconciliation-record.d.ts.map +1 -0
- package/dist/lib/telemetry/reconciliation-record.js +102 -0
- package/dist/lib/telemetry/reconciliation-record.js.map +1 -0
- package/dist/lib/telemetry/reconciliation-source.d.ts +33 -0
- package/dist/lib/telemetry/reconciliation-source.d.ts.map +1 -0
- package/dist/lib/telemetry/reconciliation-source.js +91 -0
- package/dist/lib/telemetry/reconciliation-source.js.map +1 -0
- package/dist/lib/telemetry/s3-sink.d.ts.map +1 -1
- package/dist/lib/telemetry/s3-sink.js +1 -2
- package/dist/lib/telemetry/s3-sink.js.map +1 -1
- package/dist/lib/telemetry/submission-capture.d.ts +30 -9
- package/dist/lib/telemetry/submission-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/submission-capture.js +32 -21
- package/dist/lib/telemetry/submission-capture.js.map +1 -1
- package/dist/lib/telemetry/submission-query.d.ts +32 -0
- package/dist/lib/telemetry/submission-query.d.ts.map +1 -0
- package/dist/lib/telemetry/submission-query.js +49 -0
- package/dist/lib/telemetry/submission-query.js.map +1 -0
- package/dist/lib/telemetry/submission-reader.d.ts +52 -0
- package/dist/lib/telemetry/submission-reader.d.ts.map +1 -0
- package/dist/lib/telemetry/submission-reader.js +111 -0
- package/dist/lib/telemetry/submission-reader.js.map +1 -0
- package/dist/lib/telemetry/submissions-s3-objects.d.ts +23 -0
- package/dist/lib/telemetry/submissions-s3-objects.d.ts.map +1 -0
- package/dist/lib/telemetry/submissions-s3-objects.js +132 -0
- package/dist/lib/telemetry/submissions-s3-objects.js.map +1 -0
- package/dist/lib/telemetry/submissions-s3-reader.d.ts +25 -0
- package/dist/lib/telemetry/submissions-s3-reader.d.ts.map +1 -0
- package/dist/lib/telemetry/submissions-s3-reader.js +63 -0
- package/dist/lib/telemetry/submissions-s3-reader.js.map +1 -0
- package/dist/lib/tracking-click.d.ts +13 -2
- package/dist/lib/tracking-click.d.ts.map +1 -1
- package/dist/lib/tracking-click.js +42 -4
- package/dist/lib/tracking-click.js.map +1 -1
- package/dist/plugins/loader.d.ts +17 -3
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +59 -6
- package/dist/plugins/loader.js.map +1 -1
- package/dist/scraper/cookie-jar.d.ts +10 -4
- package/dist/scraper/cookie-jar.d.ts.map +1 -1
- package/dist/scraper/cookie-jar.js +10 -5
- package/dist/scraper/cookie-jar.js.map +1 -1
- package/dist/scraper/deep-locator-candidates.d.ts +27 -5
- package/dist/scraper/deep-locator-candidates.d.ts.map +1 -1
- package/dist/scraper/deep-locator-candidates.js +57 -11
- package/dist/scraper/deep-locator-candidates.js.map +1 -1
- package/dist/scraper/deep-locator-fake.d.ts +28 -0
- package/dist/scraper/deep-locator-fake.d.ts.map +1 -1
- package/dist/scraper/deep-locator-fake.js +44 -2
- package/dist/scraper/deep-locator-fake.js.map +1 -1
- package/dist/scraper/flow-runner.d.ts +20 -0
- package/dist/scraper/flow-runner.d.ts.map +1 -1
- package/dist/scraper/flow-runner.js +81 -9
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/frame-target.d.ts +60 -14
- package/dist/scraper/frame-target.d.ts.map +1 -1
- package/dist/scraper/frame-target.js +126 -38
- package/dist/scraper/frame-target.js.map +1 -1
- package/dist/scraper/stagehand-guard.d.ts +14 -0
- package/dist/scraper/stagehand-guard.d.ts.map +1 -1
- package/dist/scraper/stagehand-guard.js +28 -8
- package/dist/scraper/stagehand-guard.js.map +1 -1
- package/dist/scraper/watchdog.d.ts +38 -0
- package/dist/scraper/watchdog.d.ts.map +1 -0
- package/dist/scraper/watchdog.js +54 -0
- package/dist/scraper/watchdog.js.map +1 -0
- package/dist/scripts/recon-browser.d.ts.map +1 -1
- package/dist/scripts/recon-browser.js +14 -3
- package/dist/scripts/recon-browser.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/dist/site-plugin.d.ts +12 -0
- package/dist/site-plugin.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -411,6 +411,41 @@ return {
|
|
|
411
411
|
|
|
412
412
|
When `auditPayload` is present, core writes it — not `data` — to the submission-envelope telemetry record. Use this to strip PII or large blobs from the audit trail while keeping the full response in the API reply. When absent, `data` is written as-is.
|
|
413
413
|
|
|
414
|
+
### Reconciliation join keys (`extractJoinKeys`)
|
|
415
|
+
|
|
416
|
+
Core has no opinion on what a reconciliation join key is named or how it's
|
|
417
|
+
shaped — that's site-specific vocabulary (an attribution vendor's click ID,
|
|
418
|
+
a job-reference composition rule, whatever the site needs). A plugin that
|
|
419
|
+
needs its submission and beacon-fire telemetry to be joinable back to its own
|
|
420
|
+
attribution provider declares an optional `extractJoinKeys` hook on its
|
|
421
|
+
`SitePlugin`:
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
export const myPlugin: SitePlugin<MyPayload, MyResponse> = {
|
|
425
|
+
extractJoinKeys: (payload) =>
|
|
426
|
+
payload.someVendorClickId ? { vendorClickId: payload.someVendorClickId } : null,
|
|
427
|
+
// ...
|
|
428
|
+
};
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
`dispatch()` (`src/plugins/loader.ts`) calls this once per submission and
|
|
432
|
+
stamps the opaque `Record<string, unknown>` result onto the submission
|
|
433
|
+
envelope and the beacon-fire record verbatim, under a `joinKeys` field —
|
|
434
|
+
core never inspects its contents. A plugin with no reconciliation needs
|
|
435
|
+
simply omits `extractJoinKeys`.
|
|
436
|
+
|
|
437
|
+
**Declaring `extractJoinKeys` also opts the plugin out of core's automatic
|
|
438
|
+
`TrackingUrl` fire.** If the site returns a post-submission click-tracking
|
|
439
|
+
URL, declare it on the plugin's `bodySchema` by composing `JobTrackingSchema`
|
|
440
|
+
(`src/lib/job-tracking.ts`) — `MySitePayloadSchema.extend(JobTrackingSchema.shape)`.
|
|
441
|
+
When a plugin has no `extractJoinKeys`, `dispatch()` fires that `TrackingUrl`
|
|
442
|
+
itself via `fireTrackingClick`, site-agnostically, after a successful submit.
|
|
443
|
+
When a plugin *does* declare `extractJoinKeys`, core assumes the plugin fires
|
|
444
|
+
its own post-submit tracking navigation (e.g. because the click and apply
|
|
445
|
+
navs must share one browser session for a vendor's device-cookie
|
|
446
|
+
attribution to work) and skips its own fire — firing both would open two
|
|
447
|
+
independent sessions against the same URL.
|
|
448
|
+
|
|
414
449
|
### Static fixtures
|
|
415
450
|
|
|
416
451
|
If Phase 3b (auxiliary fixture detection) found static JSON endpoints (markets, currencies, labels), `recon:generate` copies them to `src/sites/<id>/fixtures/`. Load them at module init via `loadFixture()` — zero per-request overhead, fails fast on deploy if the fixture is missing or stale:
|
|
@@ -585,12 +620,13 @@ See [docs/playbook.md](./docs/playbook.md#6b--metrics-signals-the-detection-ladd
|
|
|
585
620
|
|
|
586
621
|
### NDJSON telemetry files
|
|
587
622
|
|
|
588
|
-
Barnacle writes
|
|
623
|
+
Barnacle writes three append-only NDJSON files alongside its metrics:
|
|
589
624
|
|
|
590
625
|
| File | Default path | Purpose |
|
|
591
626
|
|------|-------------|---------|
|
|
592
627
|
| LLM call samples | `.barnacle/calls.ndjson` | One line per LLM/Stagehand call; feed to the `judge:llm` and `slm-self-heal` skills |
|
|
593
628
|
| Run event stream | `.barnacle/events/<runId>.ndjson` | Per-run event stream written by the event-stream subsystem; path surfaced in `/readyz` `telemetry.currentRunFile` |
|
|
629
|
+
| Submission reconciliation records | `.barnacle/submissions.ndjson` | One line per dispatch submit outcome or beacon-fire event; the durable, queryable join-key record — see [Submission record schema](#submission-record-schema) below and `GET /v1/submissions` under [Endpoints](#endpoints) |
|
|
594
630
|
|
|
595
631
|
#### LLM call sample schema
|
|
596
632
|
|
|
@@ -622,6 +658,31 @@ Every line in `.barnacle/calls.ndjson` is a JSON object with these fields (sourc
|
|
|
622
658
|
| `recon-flow-patch` | `src/scripts/recon-heal.ts` | Patch proposal from the recon-flow-patch-generator during the `recon-heal` self-healing loop |
|
|
623
659
|
| `llm-prompt-patch` | `src/scripts/llm-heal.ts` | Patch proposal from the llm-call-patch-generator during the `llm-heal` self-healing loop |
|
|
624
660
|
|
|
661
|
+
#### Submission record schema
|
|
662
|
+
|
|
663
|
+
Every `"submit"`-kind line in `.barnacle/submissions.ndjson` is a JSON object
|
|
664
|
+
validated against `submissionEnvelopeSampleSchema`
|
|
665
|
+
(`src/lib/telemetry/submission-capture.ts`, an alias of `submitRecordSchema`
|
|
666
|
+
in `src/lib/telemetry/reconciliation-record.ts`):
|
|
667
|
+
|
|
668
|
+
| Field | Type | Description |
|
|
669
|
+
|-------|------|-------------|
|
|
670
|
+
| `kind` | `"submit"` | Discriminates this record from a `"beacon"` conversion-event record sharing the same sink; defaults to `"submit"` so lines written before this field existed still parse. |
|
|
671
|
+
| `siteId` | `string` | Which plugin handled the request — the cohort dimension for reconciliation. |
|
|
672
|
+
| `requestId` | `string` | Fastify-issued correlation ID; joins a later `"beacon"` record to this one by matching `requestId`. |
|
|
673
|
+
| `joinKeys` | `Record<string, unknown> \| null` | Opaque, plugin-owned reconciliation join keys, resolved once by the plugin's `extractJoinKeys` hook (see [Reconciliation join keys](#reconciliation-join-keys-extractjoinkeys) above); `null` when the plugin has no `extractJoinKeys` or it resolved nothing. |
|
|
674
|
+
| `inboundPayload` | `unknown` | The request body the caller posted, unredacted. |
|
|
675
|
+
| `status` | `"submitted" \| "error"` | Submit outcome. |
|
|
676
|
+
| `auditPayload` | `unknown` | The plugin's `SitePluginResult.auditPayload`, or `data` when absent; `null` on errors. |
|
|
677
|
+
| `errorMessage` | `string \| null` | Failure message on errors; `null` on success. |
|
|
678
|
+
| `durationMs` | `number` | Total dispatch wall time in milliseconds. |
|
|
679
|
+
| `ts` | `string` | ISO-8601 timestamp at write time. |
|
|
680
|
+
|
|
681
|
+
A `"beacon"`-kind record shares the same sink to record a later, independent
|
|
682
|
+
beacon-fire outcome for the same `requestId` — see
|
|
683
|
+
[Submission-envelope sink](docs/telemetry-and-judging.md#submission-envelope-sink)
|
|
684
|
+
for the full schema and the `GET /v1/submissions` read path.
|
|
685
|
+
|
|
625
686
|
#### Tailing call samples with jq
|
|
626
687
|
|
|
627
688
|
```bash
|
|
@@ -678,6 +739,9 @@ process to exit on missing values; optional ones have safe defaults.
|
|
|
678
739
|
| `STAGEHAND_API_TIMEOUT_MS` | `120000` | No | Anthropic SDK request timeout (ms). Raise on slow network paths to `api.anthropic.com`. |
|
|
679
740
|
| `STAGEHAND_CONNECT_TIMEOUT_MS` | `120000` | No | TCP connect timeout for all outbound fetch calls (ms). Raised from the undici default of 10 s to match `STAGEHAND_API_TIMEOUT_MS`. |
|
|
680
741
|
| `STEEL_SESSION_TIMEOUT_MS` | `3600000` | No | Steel session wall-clock timeout (ms). Default is 1 hour; lower on plans that enforce shorter maximum session durations. |
|
|
742
|
+
| `FRAME_READY_TIMEOUT_MS` | `20000` | No | How long `resolveFrameTarget` polls for a child iframe to attach before falling back to the main frame (ms). Raise further for cross-origin OOPIFs that attach slowly under advancedStealth + proxied CDP. |
|
|
743
|
+
| `FRAME_DOCUMENT_READY_TIMEOUT_MS` | `5000` | No | How long `waitForChildFrameReady` polls a resolved child frame's `document.readyState` before proceeding anyway (ms). Independent of `FRAME_READY_TIMEOUT_MS` — this wait settles in well under a second once attached. |
|
|
744
|
+
| `FRAME_EVALUATE_TIMEOUT_MS` | `30000` | No | Watchdog budget for a single frame-scoped evaluate/candidate-probe call (ms), so a call against a racy frame fails the attempt instead of hanging indefinitely. |
|
|
681
745
|
|
|
682
746
|
### AWS Bedrock (alternative LLM provider)
|
|
683
747
|
|
|
@@ -759,13 +823,15 @@ http/net/dns. Metrics have no such constraint.
|
|
|
759
823
|
| `TELEMETRY_ENABLED` | `true` | Master switch — set `false` to disable all NDJSON telemetry writes. |
|
|
760
824
|
| `TELEMETRY_EVENTS_DIR` | `.barnacle/events` | Directory for per-run NDJSON event stream files (`<eventsDir>/<runId>.ndjson`). |
|
|
761
825
|
| `CALLS_NDJSON_PATH` | `.barnacle/calls.ndjson` | Append-only NDJSON sink for LLM/Stagehand call samples. One line per call; feed to the judge and self-heal skills. |
|
|
762
|
-
| `SUBMISSIONS_NDJSON_PATH` | `.barnacle/submissions.ndjson` | Append-only NDJSON sink for dispatch submission envelopes.
|
|
826
|
+
| `SUBMISSIONS_NDJSON_PATH` | `.barnacle/submissions.ndjson` | Append-only NDJSON sink for dispatch submission envelopes and beacon-fire outcomes. `kind:"submit"` lines (null/`"submit"`-defaulted on legacy lines) capture siteId, requestId, inbound payload, status, audit payload, and duration, plus the opaque `joinKeys` bag a plugin's `extractJoinKeys` hook resolved — the durable source-of-truth for "what did we submit for jobId X and did it succeed." `kind:"beacon"` lines record a later (or, for `beaconStatus: "skipped"`, immediate) independent beacon-fire outcome (`beaconStatus`: `fired`/`failed`/`skipped`, truncated `trackingUrl`) for the same `requestId`, so "submitted but the beacon did not fire" is measurable. A reader folds both kinds together by `requestId`, so a plugin can join runs to its own attribution provider's report without re-parsing `inboundPayload`. |
|
|
763
827
|
| `TELEMETRY_MAX_FILE_SIZE_BYTES` | `104857600` (100 MB) | Rotate/drop the calls NDJSON once it exceeds this byte count. |
|
|
764
828
|
| `TELEMETRY_MAX_RETENTION_MS` | `2592000000` (30 days) | Drop event-stream files older than this many milliseconds. |
|
|
765
829
|
| `TELEMETRY_S3_BUCKET` | — | Optional — destination bucket for the buffered S3 telemetry mirror. Sink is entirely inert (no client, no network calls) when unset. Credentials/region resolve the same way as Bedrock (`AWS_REGION`, standard SDK credential order). |
|
|
766
830
|
| `TELEMETRY_S3_PREFIX` | `telemetry` | Key prefix for uploaded NDJSON objects (`<prefix>/<calls\|submissions>/<date>/...`). |
|
|
767
831
|
| `TELEMETRY_S3_FLUSH_INTERVAL_MS` | `60000` | How often buffered lines are flushed to S3. |
|
|
768
832
|
| `TELEMETRY_S3_MAX_BUFFER_LINES` | `500` | Threshold-flush trigger — flush early if either buffer exceeds this many lines, ahead of the next scheduled interval. |
|
|
833
|
+
| `TELEMETRY_S3_READ_MAX_OBJECTS` | `200` | Upper bound on the number of S3 objects a single reconciliation read-path query is allowed to scan. |
|
|
834
|
+
| `TELEMETRY_S3_READ_CONCURRENCY` | `8` | Max concurrent object fetches for a single reconciliation read-path query. |
|
|
769
835
|
|
|
770
836
|
### LLM judging
|
|
771
837
|
|
|
@@ -913,7 +979,7 @@ Every response — success or error — uses the same envelope shape so clients
|
|
|
913
979
|
|
|
914
980
|
Full definitions: `src/api/schemas/common.ts`.
|
|
915
981
|
|
|
916
|
-
**How scraper exceptions map to API codes** (`src/plugins/loader.ts:
|
|
982
|
+
**How scraper exceptions map to API codes** (`src/plugins/loader.ts:88-92`):
|
|
917
983
|
|
|
918
984
|
- `CaptchaError` → `2004 CAPTCHA_ENCOUNTERED`
|
|
919
985
|
- `EmptyResultsError` → `2005 EMPTY_RESULTS`
|
|
@@ -951,6 +1017,7 @@ Operational routes:
|
|
|
951
1017
|
- `GET /readyz` — readiness probe (checks scraper credentials, queue depth)
|
|
952
1018
|
- `GET /docs` — Swagger UI (when `ENABLE_DOCS=true`)
|
|
953
1019
|
- `GET /v1/plugins` — authenticated plugin load report (see [Out-of-tree plugins](#out-of-tree-plugins))
|
|
1020
|
+
- `GET /v1/submissions` — authenticated, queryable submit+beacon reconciliation rows (filter by `siteId`, `requestId`, `status`, `beaconStatus`, `from`/`to`; each row's opaque `joinKeys` bag is a plugin-owned field, not filterable at this layer; see [Submission-envelope sink](docs/telemetry-and-judging.md#submission-envelope-sink))
|
|
954
1021
|
|
|
955
1022
|
## Commands
|
|
956
1023
|
|
|
@@ -1129,6 +1196,7 @@ readinessProbe:
|
|
|
1129
1196
|
- Recon playbook (step-by-step): [docs/playbook.md](./docs/playbook.md)
|
|
1130
1197
|
- Testing guide: [docs/testing.md](./docs/testing.md)
|
|
1131
1198
|
- Telemetry & LLM judging concept guide: [docs/telemetry-and-judging.md](./docs/telemetry-and-judging.md)
|
|
1199
|
+
- Submission reconciliation runbook (join Barnacle runs to a plugin's own attribution provider's report): [docs/submission-reconciliation.md](./docs/submission-reconciliation.md)
|
|
1132
1200
|
- Per-site recon findings: [docs/target-recon.md](./docs/target-recon.md) (populated after first `pnpm run recon:summarize`)
|
|
1133
1201
|
|
|
1134
1202
|
## License
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
/**
|
|
3
|
+
* Injectable options for `submissionsRoutes`. The sink path is passed in at
|
|
4
|
+
* registration time (mirrors `pluginsIntrospectionRoutes`'s `report`
|
|
5
|
+
* injection) so the route can be tested against a temp NDJSON file instead
|
|
6
|
+
* of the real `.barnacle/submissions.ndjson`.
|
|
7
|
+
*/
|
|
8
|
+
export interface SubmissionsRoutesOptions {
|
|
9
|
+
/** Override the sink path; defaults to `config.telemetry.submissionsNdjsonPath` when omitted. */
|
|
10
|
+
sinkPath?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Exposes the reconciled submit+beacon rows behind authentication, so a
|
|
14
|
+
* plugin can join runs to its own attribution provider's report over HTTP
|
|
15
|
+
* instead of re-parsing raw NDJSON. Kept out of `healthRoutes` because this
|
|
16
|
+
* payload carries applicant-run identifiers (the opaque `joinKeys` bag) —
|
|
17
|
+
* strictly more sensitive than the plugin-load report
|
|
18
|
+
* `pluginsIntrospectionRoutes` already gates behind auth.
|
|
19
|
+
*/
|
|
20
|
+
export declare function submissionsRoutes(app: FastifyInstance, options?: SubmissionsRoutesOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=submissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submissions.d.ts","sourceRoot":"","sources":["../../../src/api/routes/submissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAY/C;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,iGAAiG;IACjG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiBD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submissionsRoutes = submissionsRoutes;
|
|
4
|
+
const envelope_1 = require("../../api/helpers/envelope");
|
|
5
|
+
const submissions_1 = require("../../api/schemas/submissions");
|
|
6
|
+
const reconciliation_source_1 = require("../../lib/telemetry/reconciliation-source");
|
|
7
|
+
const submission_query_1 = require("../../lib/telemetry/submission-query");
|
|
8
|
+
/**
|
|
9
|
+
* Narrows the reader's fold output (which carries the raw `beaconTs`/
|
|
10
|
+
* `beaconDurationMs` fold detail) down to the wire contract in
|
|
11
|
+
* `reconciliationRowSchema`, renaming `beaconTrackingUrl` to `trackingUrl`.
|
|
12
|
+
*/
|
|
13
|
+
function toResponseRow(row) {
|
|
14
|
+
const { beaconTrackingUrl, beaconTs: _beaconTs, beaconDurationMs: _beaconDurationMs, ...rest } = row;
|
|
15
|
+
return { ...rest, trackingUrl: beaconTrackingUrl };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Exposes the reconciled submit+beacon rows behind authentication, so a
|
|
19
|
+
* plugin can join runs to its own attribution provider's report over HTTP
|
|
20
|
+
* instead of re-parsing raw NDJSON. Kept out of `healthRoutes` because this
|
|
21
|
+
* payload carries applicant-run identifiers (the opaque `joinKeys` bag) —
|
|
22
|
+
* strictly more sensitive than the plugin-load report
|
|
23
|
+
* `pluginsIntrospectionRoutes` already gates behind auth.
|
|
24
|
+
*/
|
|
25
|
+
async function submissionsRoutes(app, options = {}) {
|
|
26
|
+
const { sinkPath } = options;
|
|
27
|
+
app.get("/v1/submissions", {
|
|
28
|
+
onRequest: [app.authenticate],
|
|
29
|
+
schema: {
|
|
30
|
+
querystring: submissions_1.submissionsQuerystringSchema,
|
|
31
|
+
response: { 200: submissions_1.submissionsResponseSchema },
|
|
32
|
+
},
|
|
33
|
+
}, async (request) => {
|
|
34
|
+
const { limit, offset, ...filter } = request.query;
|
|
35
|
+
const rows = await (0, reconciliation_source_1.readDurableReconciliationRows)({
|
|
36
|
+
sinkPath,
|
|
37
|
+
from: filter.from,
|
|
38
|
+
to: filter.to,
|
|
39
|
+
});
|
|
40
|
+
const matched = (0, submission_query_1.queryReconciliationRows)(rows, filter);
|
|
41
|
+
const paged = matched.slice(offset, offset + limit);
|
|
42
|
+
return (0, envelope_1.successEnvelope)({
|
|
43
|
+
submissions: paged.map(toResponseRow),
|
|
44
|
+
total: matched.length,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=submissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../../src/api/routes/submissions.ts"],"names":[],"mappings":";;;AAEA,qDAAyD;AAKzD,2DAAoG;AACpG,iFAAsF;AACtF,uEAA2E;AAc3E;;;;GAIG;AACH,SAAS,aAAa,CAAC,GAAsB;IAC3C,MAAM,EACJ,iBAAiB,EACjB,QAAQ,EAAE,SAAS,EACnB,gBAAgB,EAAE,iBAAiB,EACnC,GAAG,IAAI,EACR,GAAG,GAAG,CAAC;IACR,OAAO,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC;AACrD,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,4BACV,GAAoB,EACpB,OAAO,GAA6B,EAAE;IAEtC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE7B,GAAG,CAAC,GAAG,CACL,iBAAiB,EACjB;QACE,SAAS,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC;QAC7B,MAAM,EAAE;YACN,WAAW,EAAE,0CAA4B;YACzC,QAAQ,EAAE,EAAE,GAAG,EAAE,uCAAyB,EAAE;SAC7C;KACF,EACD,KAAK,EAAE,OAAO,EAAE,EAAE;QAChB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,IAAA,qDAA6B,EAAC;YAC/C,QAAQ;YACR,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,EAAE,EAAE,MAAM,CAAC,EAAE;SACd,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAA,0CAAuB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;QAEpD,OAAO,IAAA,0BAAe,EAAC;YACrB,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;YACrC,KAAK,EAAE,OAAO,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
/**
|
|
3
|
+
* Upper bound on `limit` so a query can't ask the read path to serialize the
|
|
4
|
+
* entire (potentially 100 MB) submissions sink into one response.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SUBMISSIONS_QUERY_LIMIT_MAX = 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Querystring contract for the submissions read route. Every field is
|
|
9
|
+
* optional so a caller can filter by `siteId`/`requestId`, submit/beacon
|
|
10
|
+
* outcome, or a time window, and page through results. Site-specific join
|
|
11
|
+
* keys live in the opaque `joinKeys` bag on each row and are not filterable
|
|
12
|
+
* here — filter client-side, or on `siteId`/`requestId` first.
|
|
13
|
+
*/
|
|
14
|
+
export declare const submissionsQuerystringSchema: z.ZodObject<{
|
|
15
|
+
siteId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>;
|
|
16
|
+
requestId: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>;
|
|
17
|
+
status: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodEnum<{
|
|
18
|
+
error: "error";
|
|
19
|
+
submitted: "submitted";
|
|
20
|
+
}>>>;
|
|
21
|
+
beaconStatus: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
failed: "failed";
|
|
23
|
+
fired: "fired";
|
|
24
|
+
not_fired: "not_fired";
|
|
25
|
+
skipped: "skipped";
|
|
26
|
+
}>>>;
|
|
27
|
+
from: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodISODateTime>>;
|
|
28
|
+
to: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodISODateTime>>;
|
|
29
|
+
limit: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
|
|
30
|
+
offset: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type SubmissionsQuerystring = z.infer<typeof submissionsQuerystringSchema>;
|
|
33
|
+
/**
|
|
34
|
+
* One reconciled per-run row: the submit record's opaque `joinKeys` bag and
|
|
35
|
+
* outcome, plus the beacon-fire dimension folded on by `requestId`. Derived
|
|
36
|
+
* from `submitRecordSchema` (feat-002's durable record) rather than
|
|
37
|
+
* restated, so a field added to the writer can't silently drift from what
|
|
38
|
+
* the read path claims to expose — the same re-export-not-duplicate pattern
|
|
39
|
+
* as `src/api/schemas/telemetry.ts`. `inboundPayload`/`auditPayload` are
|
|
40
|
+
* omitted: they're the opaque blob this route exists to stop callers from
|
|
41
|
+
* having to re-parse.
|
|
42
|
+
*/
|
|
43
|
+
export declare const reconciliationRowSchema: z.ZodObject<{
|
|
44
|
+
siteId: z.ZodString;
|
|
45
|
+
requestId: z.ZodString;
|
|
46
|
+
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
47
|
+
status: z.ZodEnum<{
|
|
48
|
+
error: "error";
|
|
49
|
+
submitted: "submitted";
|
|
50
|
+
}>;
|
|
51
|
+
errorMessage: z.ZodNullable<z.ZodString>;
|
|
52
|
+
durationMs: z.ZodNumber;
|
|
53
|
+
ts: z.ZodString;
|
|
54
|
+
beaconStatus: z.ZodEnum<{
|
|
55
|
+
failed: "failed";
|
|
56
|
+
fired: "fired";
|
|
57
|
+
not_fired: "not_fired";
|
|
58
|
+
skipped: "skipped";
|
|
59
|
+
}>;
|
|
60
|
+
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export type ReconciliationRow = z.infer<typeof reconciliationRowSchema>;
|
|
63
|
+
/**
|
|
64
|
+
* Response contract for the submissions read route: the standard envelope
|
|
65
|
+
* plus the reconciled rows and a total count for pagination.
|
|
66
|
+
*/
|
|
67
|
+
export declare const submissionsResponseSchema: z.ZodObject<{
|
|
68
|
+
status: z.ZodObject<{
|
|
69
|
+
httpStatus: z.ZodUnion<[z.ZodEnum<{
|
|
70
|
+
BAD_REQUEST: "BAD_REQUEST";
|
|
71
|
+
FORBIDDEN: "FORBIDDEN";
|
|
72
|
+
GATEWAY_TIMEOUT: "GATEWAY_TIMEOUT";
|
|
73
|
+
INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR";
|
|
74
|
+
NOT_FOUND: "NOT_FOUND";
|
|
75
|
+
OK: "OK";
|
|
76
|
+
SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE";
|
|
77
|
+
TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS";
|
|
78
|
+
UNAUTHORIZED: "UNAUTHORIZED";
|
|
79
|
+
}>, z.ZodString]>;
|
|
80
|
+
dateTime: z.ZodString;
|
|
81
|
+
details: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
82
|
+
code: z.ZodNumber;
|
|
83
|
+
codeDescription: z.ZodString;
|
|
84
|
+
detailType: z.ZodOptional<z.ZodString>;
|
|
85
|
+
message: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.core.$loose>>>;
|
|
87
|
+
}, z.core.$loose>;
|
|
88
|
+
submissions: z.ZodArray<z.ZodObject<{
|
|
89
|
+
siteId: z.ZodString;
|
|
90
|
+
requestId: z.ZodString;
|
|
91
|
+
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
92
|
+
status: z.ZodEnum<{
|
|
93
|
+
error: "error";
|
|
94
|
+
submitted: "submitted";
|
|
95
|
+
}>;
|
|
96
|
+
errorMessage: z.ZodNullable<z.ZodString>;
|
|
97
|
+
durationMs: z.ZodNumber;
|
|
98
|
+
ts: z.ZodString;
|
|
99
|
+
beaconStatus: z.ZodEnum<{
|
|
100
|
+
failed: "failed";
|
|
101
|
+
fired: "fired";
|
|
102
|
+
not_fired: "not_fired";
|
|
103
|
+
skipped: "skipped";
|
|
104
|
+
}>;
|
|
105
|
+
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
106
|
+
}, z.core.$strip>>;
|
|
107
|
+
total: z.ZodNumber;
|
|
108
|
+
}, z.core.$strip>;
|
|
109
|
+
export type SubmissionsResponse = z.infer<typeof submissionsResponseSchema>;
|
|
110
|
+
//# sourceMappingURL=submissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submissions.d.ts","sourceRoot":"","sources":["../../../src/api/schemas/submissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAK3B;;;GAGG;AACH,eAAO,MAAM,2BAA2B,OAAO,CAAC;AA6BhD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;iBAevC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;iBAKhC,CAAC;AAEL,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submissionsResponseSchema = exports.reconciliationRowSchema = exports.submissionsQuerystringSchema = exports.SUBMISSIONS_QUERY_LIMIT_MAX = void 0;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
const common_1 = require("../../api/schemas/common");
|
|
6
|
+
const reconciliation_record_1 = require("../../lib/telemetry/reconciliation-record");
|
|
7
|
+
/**
|
|
8
|
+
* Upper bound on `limit` so a query can't ask the read path to serialize the
|
|
9
|
+
* entire (potentially 100 MB) submissions sink into one response.
|
|
10
|
+
*/
|
|
11
|
+
exports.SUBMISSIONS_QUERY_LIMIT_MAX = 1000;
|
|
12
|
+
const DEFAULT_LIMIT = 100;
|
|
13
|
+
const DEFAULT_OFFSET = 0;
|
|
14
|
+
/**
|
|
15
|
+
* Query params arrive as strings (or an empty string for a present-but-blank
|
|
16
|
+
* value, e.g. `?limit=`). Both cases mean "not provided" for an optional
|
|
17
|
+
* filter, so they're normalized to `undefined` ahead of the real schema
|
|
18
|
+
* rather than treating `""` as a literal filter value.
|
|
19
|
+
*/
|
|
20
|
+
function blankToUndefined(value) {
|
|
21
|
+
return value === "" ? undefined : value;
|
|
22
|
+
}
|
|
23
|
+
const optionalTrimmedString = () => v4_1.z.preprocess(blankToUndefined, v4_1.z.string().optional());
|
|
24
|
+
/**
|
|
25
|
+
* The read path's beacon-status fold: the record-layer `beaconStatus`
|
|
26
|
+
* options (`beaconEventSchema.shape.beaconStatus`) plus `"not_fired"`, the
|
|
27
|
+
* value `submission-reader.ts` folds in when no beacon line ever arrived.
|
|
28
|
+
* Derived rather than restated so a status added at the record layer can't
|
|
29
|
+
* silently drift from what this read path advertises.
|
|
30
|
+
*/
|
|
31
|
+
const reconciliationBeaconStatusSchema = v4_1.z.enum([
|
|
32
|
+
...reconciliation_record_1.beaconEventSchema.shape.beaconStatus.options,
|
|
33
|
+
"not_fired",
|
|
34
|
+
]);
|
|
35
|
+
/**
|
|
36
|
+
* Querystring contract for the submissions read route. Every field is
|
|
37
|
+
* optional so a caller can filter by `siteId`/`requestId`, submit/beacon
|
|
38
|
+
* outcome, or a time window, and page through results. Site-specific join
|
|
39
|
+
* keys live in the opaque `joinKeys` bag on each row and are not filterable
|
|
40
|
+
* here — filter client-side, or on `siteId`/`requestId` first.
|
|
41
|
+
*/
|
|
42
|
+
exports.submissionsQuerystringSchema = v4_1.z.object({
|
|
43
|
+
siteId: optionalTrimmedString(),
|
|
44
|
+
requestId: optionalTrimmedString(),
|
|
45
|
+
status: v4_1.z.preprocess(blankToUndefined, reconciliation_record_1.submitRecordSchema.shape.status.optional()),
|
|
46
|
+
beaconStatus: v4_1.z.preprocess(blankToUndefined, reconciliationBeaconStatusSchema.optional()),
|
|
47
|
+
from: v4_1.z.preprocess(blankToUndefined, v4_1.z.iso.datetime({ offset: true }).optional()),
|
|
48
|
+
to: v4_1.z.preprocess(blankToUndefined, v4_1.z.iso.datetime({ offset: true }).optional()),
|
|
49
|
+
limit: v4_1.z.preprocess(blankToUndefined, v4_1.z.coerce.number().int().positive().max(exports.SUBMISSIONS_QUERY_LIMIT_MAX).default(DEFAULT_LIMIT)),
|
|
50
|
+
offset: v4_1.z.preprocess(blankToUndefined, v4_1.z.coerce.number().int().nonnegative().default(DEFAULT_OFFSET)),
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* One reconciled per-run row: the submit record's opaque `joinKeys` bag and
|
|
54
|
+
* outcome, plus the beacon-fire dimension folded on by `requestId`. Derived
|
|
55
|
+
* from `submitRecordSchema` (feat-002's durable record) rather than
|
|
56
|
+
* restated, so a field added to the writer can't silently drift from what
|
|
57
|
+
* the read path claims to expose — the same re-export-not-duplicate pattern
|
|
58
|
+
* as `src/api/schemas/telemetry.ts`. `inboundPayload`/`auditPayload` are
|
|
59
|
+
* omitted: they're the opaque blob this route exists to stop callers from
|
|
60
|
+
* having to re-parse.
|
|
61
|
+
*/
|
|
62
|
+
exports.reconciliationRowSchema = reconciliation_record_1.submitRecordSchema
|
|
63
|
+
.omit({ kind: true, inboundPayload: true, auditPayload: true })
|
|
64
|
+
.extend({
|
|
65
|
+
beaconStatus: reconciliationBeaconStatusSchema,
|
|
66
|
+
trackingUrl: v4_1.z.string().nullable(),
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Response contract for the submissions read route: the standard envelope
|
|
70
|
+
* plus the reconciled rows and a total count for pagination.
|
|
71
|
+
*/
|
|
72
|
+
exports.submissionsResponseSchema = v4_1.z.object({
|
|
73
|
+
status: common_1.statusSchema,
|
|
74
|
+
submissions: v4_1.z.array(exports.reconciliationRowSchema),
|
|
75
|
+
total: v4_1.z.number().int().nonnegative(),
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=submissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submissions.js","sourceRoot":"","sources":["../../../src/api/schemas/submissions.ts"],"names":[],"mappings":";;;AAAA,+BAA2B;AAE3B,iDAAoD;AACpD,iFAA8F;AAE9F;;;GAGG;AACU,QAAA,2BAA2B,GAAG,IAAI,CAAC;AAEhD,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AAC1C,CAAC;AAED,MAAM,qBAAqB,GAAG,GAAG,EAAE,CAAC,MAAC,CAAC,UAAU,CAAC,gBAAgB,EAAE,MAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;AAE1F;;;;;;GAMG;AACH,MAAM,gCAAgC,GAAG,MAAC,CAAC,IAAI,CAAC;IAC9C,GAAG,yCAAiB,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO;IAC/C,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;GAMG;AACU,QAAA,4BAA4B,GAAG,MAAC,CAAC,MAAM,CAAC;IACnD,MAAM,EAAE,qBAAqB,EAAE;IAC/B,SAAS,EAAE,qBAAqB,EAAE;IAClC,MAAM,EAAE,MAAC,CAAC,UAAU,CAAC,gBAAgB,EAAE,0CAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IAClF,YAAY,EAAE,MAAC,CAAC,UAAU,CAAC,gBAAgB,EAAE,gCAAgC,CAAC,QAAQ,EAAE,CAAC;IACzF,IAAI,EAAE,MAAC,CAAC,UAAU,CAAC,gBAAgB,EAAE,MAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjF,EAAE,EAAE,MAAC,CAAC,UAAU,CAAC,gBAAgB,EAAE,MAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/E,KAAK,EAAE,MAAC,CAAC,UAAU,CACjB,gBAAgB,EAChB,MAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,QAAA,2BAA2B,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAC3F;IACD,MAAM,EAAE,MAAC,CAAC,UAAU,CAClB,gBAAgB,EAChB,MAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAC9D;CACF,CAAC,CAAC;AAIH;;;;;;;;;GASG;AACU,QAAA,uBAAuB,GAAG,0CAAkB;KACtD,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;KAC9D,MAAM,CAAC;IACN,YAAY,EAAE,gCAAgC;IAC9C,WAAW,EAAE,MAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAIL;;;GAGG;AACU,QAAA,yBAAyB,GAAG,MAAC,CAAC,MAAM,CAAC;IAChD,MAAM,EAAE,qBAAY;IACpB,WAAW,EAAE,MAAC,CAAC,KAAK,CAAC,QAAA,uBAAuB,CAAC;IAC7C,KAAK,EAAE,MAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CACtC,CAAC,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -60,6 +60,28 @@ export interface AppConfig {
|
|
|
60
60
|
connectTimeoutMs: number;
|
|
61
61
|
/** Steel session wall-clock timeout in ms. Default is 1 hour; lower via STEEL_SESSION_TIMEOUT_MS on plans with shorter limits. */
|
|
62
62
|
steelSessionTimeoutMs: number;
|
|
63
|
+
/**
|
|
64
|
+
* How long `resolveFrameTarget` polls `page.frames()` for a child iframe
|
|
65
|
+
* to attach before falling back to the main-frame target. Raised from a
|
|
66
|
+
* hardcoded 5 s default because cross-origin OOPIFs (e.g. Talemetry's
|
|
67
|
+
* apply iframe) regularly exceed 5 s to attach under advancedStealth +
|
|
68
|
+
* proxied CDP, even though a bare session attaches in ~3-4 s.
|
|
69
|
+
*/
|
|
70
|
+
frameReadyTimeoutMs: number;
|
|
71
|
+
/**
|
|
72
|
+
* How long `waitForChildFrameReady` polls a resolved child frame's
|
|
73
|
+
* `document.readyState` before proceeding anyway. Kept separate from
|
|
74
|
+
* `frameReadyTimeoutMs` — this wait settles in well under a second once
|
|
75
|
+
* the frame has attached, so raising the attach budget must not stretch
|
|
76
|
+
* this one too.
|
|
77
|
+
*/
|
|
78
|
+
frameDocumentReadyTimeoutMs: number;
|
|
79
|
+
/**
|
|
80
|
+
* Watchdog budget for a single frame-scoped `evaluate`/candidate-probe
|
|
81
|
+
* call (e.g. `deepLocator().count()`/`.click()`), so a call against a
|
|
82
|
+
* racy OOPIF fails the attempt instead of hanging the step indefinitely.
|
|
83
|
+
*/
|
|
84
|
+
frameEvaluateTimeoutMs: number;
|
|
63
85
|
};
|
|
64
86
|
bedrock: {
|
|
65
87
|
region: string;
|
|
@@ -133,6 +155,18 @@ export interface AppConfig {
|
|
|
133
155
|
flushIntervalMs: number;
|
|
134
156
|
/** `TELEMETRY_S3_MAX_BUFFER_LINES` — threshold-flush trigger per buffer. */
|
|
135
157
|
maxBufferLines: number;
|
|
158
|
+
/**
|
|
159
|
+
* `TELEMETRY_S3_READ_MAX_OBJECTS` — upper bound on the number of S3
|
|
160
|
+
* objects a single reconciliation read-path query is allowed to scan,
|
|
161
|
+
* so a query spanning months of shipped NDJSON cannot fan out
|
|
162
|
+
* unbounded S3 GETs or blow the response budget.
|
|
163
|
+
*/
|
|
164
|
+
readMaxObjects: number;
|
|
165
|
+
/**
|
|
166
|
+
* `TELEMETRY_S3_READ_CONCURRENCY` — max concurrent object fetches for
|
|
167
|
+
* a single reconciliation read-path query.
|
|
168
|
+
*/
|
|
169
|
+
readConcurrency: number;
|
|
136
170
|
};
|
|
137
171
|
};
|
|
138
172
|
judging: {
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QACJ,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IACF;;;;;;;OAOG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE;QACP;;;;;;;WAOG;QACH,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC;QAClC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;QACtC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;QACzC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,OAAO,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,uBAAuB,EAAE,MAAM,CAAC;QAChC;;;;;;;WAOG;QACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,+EAA+E;QAC/E,UAAU,EAAE,OAAO,CAAC;QACpB,8FAA8F;QAC9F,kBAAkB,EAAE,MAAM,CAAC;QAC3B,6HAA6H;QAC7H,gBAAgB,EAAE,MAAM,CAAC;QACzB,kIAAkI;QAClI,qBAAqB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE;QACJ,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IACF;;;;;;;OAOG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE;QACP;;;;;;;WAOG;QACH,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC;QAClC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;QACtC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;QACzC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,OAAO,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,uBAAuB,EAAE,MAAM,CAAC;QAChC;;;;;;;WAOG;QACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,+EAA+E;QAC/E,UAAU,EAAE,OAAO,CAAC;QACpB,8FAA8F;QAC9F,kBAAkB,EAAE,MAAM,CAAC;QAC3B,6HAA6H;QAC7H,gBAAgB,EAAE,MAAM,CAAC;QACzB,kIAAkI;QAClI,qBAAqB,EAAE,MAAM,CAAC;QAC9B;;;;;;WAMG;QACH,mBAAmB,EAAE,MAAM,CAAC;QAC5B;;;;;;WAMG;QACH,2BAA2B,EAAE,MAAM,CAAC;QACpC;;;;WAIG;QACH,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;IACF,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;QACjC,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,EAAE;QACT;;;;WAIG;QACH,OAAO,EAAE,OAAO,CAAC;QACjB;;;;;WAKG;QACH,SAAS,EAAE,MAAM,CAAC;QAClB;;;;WAIG;QACH,eAAe,EAAE,MAAM,CAAC;QACxB;;;;;;;WAOG;QACH,qBAAqB,EAAE,MAAM,CAAC;QAC9B;;;;WAIG;QACH,gBAAgB,EAAE,MAAM,CAAC;QACzB;;;WAGG;QACH,cAAc,EAAE,MAAM,CAAC;QACvB;;;;WAIG;QACH,EAAE,EAAE;YACF,8EAA8E;YAC9E,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;YAC3B,sEAAsE;YACtE,MAAM,EAAE,MAAM,CAAC;YACf,kEAAkE;YAClE,eAAe,EAAE,MAAM,CAAC;YACxB,4EAA4E;YAC5E,cAAc,EAAE,MAAM,CAAC;YACvB;;;;;eAKG;YACH,cAAc,EAAE,MAAM,CAAC;YACvB;;;eAGG;YACH,eAAe,EAAE,MAAM,CAAC;SACzB,CAAC;KACH,CAAC;IACF,OAAO,EAAE;QACP;;;;WAIG;QACH,KAAK,EAAE,MAAM,CAAC;QACd;;;WAGG;QACH,WAAW,EAAE,MAAM,CAAC;QACpB;;;WAGG;QACH,SAAS,EAAE,MAAM,CAAC;QAClB;;;WAGG;QACH,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;;;;OAKG;IACH,QAAQ,EAAE;QACR,iEAAiE;QACjE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;QAC3B,sGAAsG;QACtG,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;KAC/B,CAAC;IACF,QAAQ,EAAE;QACR;;;WAGG;QACH,aAAa,EAAE,MAAM,CAAC;QACtB;;;WAGG;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB;;;WAGG;QACH,gBAAgB,EAAE,MAAM,CAAC;QACzB;;;WAGG;QACH,aAAa,EAAE,MAAM,CAAC;QACtB;;;WAGG;QACH,YAAY,EAAE,MAAM,CAAC;QACrB;;;WAGG;QACH,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,EAAE;QACP;;;WAGG;QACH,YAAY,EAAE,OAAO,CAAC;QACtB;;;;WAIG;QACH,cAAc,EAAE,OAAO,CAAC;QACxB,mEAAmE;QACnE,SAAS,EAAE,MAAM,CAAC;QAClB,4CAA4C;QAC5C,UAAU,EAAE,MAAM,CAAC;QACnB,4DAA4D;QAC5D,OAAO,EAAE,MAAM,CAAC;QAChB,qEAAqE;QACrE,GAAG,EAAE,MAAM,CAAC;QACZ,4DAA4D;QAC5D,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;;;OAIG;IACH,OAAO,EAAE;QACP;;;;WAIG;QACH,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B;;;WAGG;QACH,MAAM,EAAE,OAAO,CAAC;QAChB;;;;;WAKG;QACH,OAAO,EAAE,MAAM,CAAC;QAChB;;;;;WAKG;QACH,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;KAC/B,CAAC;CACH;AAaD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,SAAS,CA4HtC;AAED,eAAO,MAAM,MAAM,EAAE,SAAwB,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -67,6 +67,9 @@ function loadConfig() {
|
|
|
67
67
|
anthropicTimeoutMs: (0, env_1.getNumericEnv)("STAGEHAND_API_TIMEOUT_MS", 120_000),
|
|
68
68
|
connectTimeoutMs: (0, env_1.getNumericEnv)("STAGEHAND_CONNECT_TIMEOUT_MS", 120_000),
|
|
69
69
|
steelSessionTimeoutMs: (0, env_1.getNumericEnv)("STEEL_SESSION_TIMEOUT_MS", 3_600_000),
|
|
70
|
+
frameReadyTimeoutMs: (0, env_1.getNumericEnv)("FRAME_READY_TIMEOUT_MS", 20_000),
|
|
71
|
+
frameDocumentReadyTimeoutMs: (0, env_1.getNumericEnv)("FRAME_DOCUMENT_READY_TIMEOUT_MS", 5_000),
|
|
72
|
+
frameEvaluateTimeoutMs: (0, env_1.getNumericEnv)("FRAME_EVALUATE_TIMEOUT_MS", 30_000),
|
|
70
73
|
},
|
|
71
74
|
bedrock: {
|
|
72
75
|
region: (0, env_1.getEnv)("AWS_REGION", "us-east-1"),
|
|
@@ -98,6 +101,8 @@ function loadConfig() {
|
|
|
98
101
|
prefix: (0, env_1.getEnv)("TELEMETRY_S3_PREFIX", "telemetry"),
|
|
99
102
|
flushIntervalMs: (0, env_1.getNumericEnv)("TELEMETRY_S3_FLUSH_INTERVAL_MS", 60_000),
|
|
100
103
|
maxBufferLines: (0, env_1.getNumericEnv)("TELEMETRY_S3_MAX_BUFFER_LINES", 500),
|
|
104
|
+
readMaxObjects: (0, env_1.getNumericEnv)("TELEMETRY_S3_READ_MAX_OBJECTS", 200),
|
|
105
|
+
readConcurrency: (0, env_1.getNumericEnv)("TELEMETRY_S3_READ_CONCURRENCY", 8),
|
|
101
106
|
},
|
|
102
107
|
},
|
|
103
108
|
judging: {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;AAAA,mCAAuF;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only NDJSON writer for beacon-fire outcomes. A `"fired"`/`"failed"`
|
|
3
|
+
* beacon resolves strictly after dispatch already returned and wrote its
|
|
4
|
+
* submit line (see `tracking-click.ts`'s fire-and-forget click); a
|
|
5
|
+
* `"skipped"` beacon is instead written synchronously by `dispatch()` itself,
|
|
6
|
+
* before it returns, when there is no `TrackingUrl` to fire-and-forget at
|
|
7
|
+
* all. Either way it is recorded as its own `kind:"beacon"` line rather than
|
|
8
|
+
* a mutation of the submit line — a reader folds the two kinds together by
|
|
9
|
+
* `requestId` (see `reconciliation-record.ts`, `submission-reader.ts`).
|
|
10
|
+
*
|
|
11
|
+
* Writes to the SAME sink as submit lines (`appendSubmissionSinkLine`,
|
|
12
|
+
* feat-003), which is what lets the S3 mirror carry beacon lines for free
|
|
13
|
+
* with zero `s3-sink.ts` changes.
|
|
14
|
+
*/
|
|
15
|
+
import type { z } from "zod/v4";
|
|
16
|
+
import type { beaconEventSchema } from "../../lib/telemetry/reconciliation-record";
|
|
17
|
+
/** Validated shape of one beacon-event sample. */
|
|
18
|
+
export type BeaconEventSample = z.infer<typeof beaconEventSchema>;
|
|
19
|
+
/**
|
|
20
|
+
* Input to `captureBeaconEvent` — `ts` and `kind` are derived internally so
|
|
21
|
+
* callers omit them.
|
|
22
|
+
*/
|
|
23
|
+
export type BeaconEventInput = Omit<BeaconEventSample, "ts" | "kind">;
|
|
24
|
+
/** Options for `captureBeaconEvent`. */
|
|
25
|
+
export interface CaptureBeaconEventOptions {
|
|
26
|
+
/** Override the sink path; used in tests to avoid touching the real file. */
|
|
27
|
+
sinkPath?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Appends one validated NDJSON line for a beacon-fire outcome to the
|
|
31
|
+
* configured submissions sink. Errors are logged and swallowed — telemetry
|
|
32
|
+
* must never break the happy path, matching the never-throw contract
|
|
33
|
+
* `captureSubmissionEnvelope` enforces (submission-capture.ts:52-56); the
|
|
34
|
+
* beacon caller (tracking-click) is already fire-and-forget.
|
|
35
|
+
*/
|
|
36
|
+
export declare function captureBeaconEvent(input: BeaconEventInput, opts?: CaptureBeaconEventOptions): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=beacon-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-capture.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAO/E,kDAAkD;AAClD,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,iBAAiB,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;AAEtE,wCAAwC;AACxC,MAAM,WAAW,yBAAyB;IACxC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,gBAAgB,EACvB,IAAI,GAAE,yBAA8B,GACnC,OAAO,CAAC,IAAI,CAAC,CAef"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Append-only NDJSON writer for beacon-fire outcomes. A `"fired"`/`"failed"`
|
|
4
|
+
* beacon resolves strictly after dispatch already returned and wrote its
|
|
5
|
+
* submit line (see `tracking-click.ts`'s fire-and-forget click); a
|
|
6
|
+
* `"skipped"` beacon is instead written synchronously by `dispatch()` itself,
|
|
7
|
+
* before it returns, when there is no `TrackingUrl` to fire-and-forget at
|
|
8
|
+
* all. Either way it is recorded as its own `kind:"beacon"` line rather than
|
|
9
|
+
* a mutation of the submit line — a reader folds the two kinds together by
|
|
10
|
+
* `requestId` (see `reconciliation-record.ts`, `submission-reader.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Writes to the SAME sink as submit lines (`appendSubmissionSinkLine`,
|
|
13
|
+
* feat-003), which is what lets the S3 mirror carry beacon lines for free
|
|
14
|
+
* with zero `s3-sink.ts` changes.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.captureBeaconEvent = captureBeaconEvent;
|
|
18
|
+
const date_fns_1 = require("date-fns");
|
|
19
|
+
const config_1 = require("../../config");
|
|
20
|
+
const logging_1 = require("../../lib/logging");
|
|
21
|
+
const submission_capture_1 = require("../../lib/telemetry/submission-capture");
|
|
22
|
+
const logger = (0, logging_1.getLogger)({ name: "telemetry/beacon-capture" });
|
|
23
|
+
const TRACKING_URL_MAX_LENGTH = 120;
|
|
24
|
+
/**
|
|
25
|
+
* Appends one validated NDJSON line for a beacon-fire outcome to the
|
|
26
|
+
* configured submissions sink. Errors are logged and swallowed — telemetry
|
|
27
|
+
* must never break the happy path, matching the never-throw contract
|
|
28
|
+
* `captureSubmissionEnvelope` enforces (submission-capture.ts:52-56); the
|
|
29
|
+
* beacon caller (tracking-click) is already fire-and-forget.
|
|
30
|
+
*/
|
|
31
|
+
async function captureBeaconEvent(input, opts = {}) {
|
|
32
|
+
const sinkPath = opts.sinkPath ?? config_1.config.telemetry.submissionsNdjsonPath;
|
|
33
|
+
const sample = {
|
|
34
|
+
...input,
|
|
35
|
+
kind: "beacon",
|
|
36
|
+
trackingUrl: input.trackingUrl?.slice(0, TRACKING_URL_MAX_LENGTH) ?? null,
|
|
37
|
+
ts: (0, date_fns_1.formatISO)(new Date()),
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
const line = `${JSON.stringify(sample)}\n`;
|
|
41
|
+
await (0, submission_capture_1.appendSubmissionSinkLine)(sinkPath, line);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
logger.error(`captureBeaconEvent: failed to write to ${sinkPath}: ${String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=beacon-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-capture.js","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,uCAAqC;AAGrC,qCAAkC;AAClC,2CAA0C;AAE1C,2EAA8E;AAE9E,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,CAAC,CAAC;AAE/D,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAiBpC;;;;;;GAMG;AACI,KAAK,6BACV,KAAuB,EACvB,IAAI,GAA8B,EAAE;IAEpC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC;IACzE,MAAM,MAAM,GAAsB;QAChC,GAAG,KAAK;QACR,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,EAAE,uBAAuB,CAAC,IAAI,IAAI;QACzE,EAAE,EAAE,IAAA,oBAAS,EAAC,IAAI,IAAI,EAAE,CAAC;KAC1B,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;QAC3C,MAAM,IAAA,6CAAwB,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,0CAA0C,QAAQ,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;AACH,CAAC"}
|