@enricai/barnacle 1.6.11 → 1.6.13
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 +113 -9
- package/dist/api/schemas/submissions.d.ts +14 -0
- package/dist/api/schemas/submissions.d.ts.map +1 -1
- package/dist/api/schemas/submissions.js +1 -0
- package/dist/api/schemas/submissions.js.map +1 -1
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/lib/telemetry/beacon-capture.d.ts +45 -2
- package/dist/lib/telemetry/beacon-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/beacon-capture.js +36 -0
- package/dist/lib/telemetry/beacon-capture.js.map +1 -1
- package/dist/lib/telemetry/reconciliation-record.d.ts +50 -2
- package/dist/lib/telemetry/reconciliation-record.d.ts.map +1 -1
- package/dist/lib/telemetry/reconciliation-record.js +60 -7
- package/dist/lib/telemetry/reconciliation-record.js.map +1 -1
- package/dist/lib/telemetry/reconciliation-source.d.ts +7 -1
- package/dist/lib/telemetry/reconciliation-source.d.ts.map +1 -1
- package/dist/lib/telemetry/reconciliation-source.js +21 -5
- package/dist/lib/telemetry/reconciliation-source.js.map +1 -1
- package/dist/lib/telemetry/run-telemetry.d.ts +67 -0
- package/dist/lib/telemetry/run-telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry/run-telemetry.js +55 -0
- package/dist/lib/telemetry/run-telemetry.js.map +1 -0
- package/dist/lib/telemetry/submission-capture.d.ts +11 -4
- package/dist/lib/telemetry/submission-capture.d.ts.map +1 -1
- package/dist/lib/telemetry/submission-capture.js +1 -0
- package/dist/lib/telemetry/submission-capture.js.map +1 -1
- package/dist/lib/telemetry/submission-reader.d.ts +11 -3
- package/dist/lib/telemetry/submission-reader.d.ts.map +1 -1
- package/dist/lib/telemetry/submission-reader.js +32 -8
- package/dist/lib/telemetry/submission-reader.js.map +1 -1
- package/dist/lib/tracking-click.d.ts.map +1 -1
- package/dist/lib/tracking-click.js +19 -0
- package/dist/lib/tracking-click.js.map +1 -1
- package/dist/plugins/loader.d.ts +20 -0
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +94 -17
- package/dist/plugins/loader.js.map +1 -1
- package/dist/scraper/deep-locator-actuate.d.ts +94 -0
- package/dist/scraper/deep-locator-actuate.d.ts.map +1 -0
- package/dist/scraper/deep-locator-actuate.js +216 -0
- package/dist/scraper/deep-locator-actuate.js.map +1 -0
- package/dist/scraper/deep-locator-candidates.d.ts +105 -18
- package/dist/scraper/deep-locator-candidates.d.ts.map +1 -1
- package/dist/scraper/deep-locator-candidates.js +238 -46
- package/dist/scraper/deep-locator-candidates.js.map +1 -1
- package/dist/scraper/deep-locator-click.d.ts +71 -0
- package/dist/scraper/deep-locator-click.d.ts.map +1 -0
- package/dist/scraper/deep-locator-click.js +71 -0
- package/dist/scraper/deep-locator-click.js.map +1 -0
- package/dist/scraper/deep-locator-fake.d.ts +344 -14
- package/dist/scraper/deep-locator-fake.d.ts.map +1 -1
- package/dist/scraper/deep-locator-fake.js +509 -7
- package/dist/scraper/deep-locator-fake.js.map +1 -1
- package/dist/scraper/deep-locator-scan.d.ts +220 -0
- package/dist/scraper/deep-locator-scan.d.ts.map +1 -0
- package/dist/scraper/deep-locator-scan.js +386 -0
- package/dist/scraper/deep-locator-scan.js.map +1 -0
- package/dist/scraper/fake-timer-advance.d.ts +47 -0
- package/dist/scraper/fake-timer-advance.d.ts.map +1 -0
- package/dist/scraper/fake-timer-advance.js +44 -0
- package/dist/scraper/fake-timer-advance.js.map +1 -0
- package/dist/scraper/flow-runner.d.ts +36 -1
- package/dist/scraper/flow-runner.d.ts.map +1 -1
- package/dist/scraper/flow-runner.js +354 -56
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/frame-target.d.ts +28 -0
- package/dist/scraper/frame-target.d.ts.map +1 -1
- package/dist/scraper/frame-target.js +30 -0
- package/dist/scraper/frame-target.js.map +1 -1
- package/dist/scraper/session-browserbase.d.ts +13 -0
- package/dist/scraper/session-browserbase.d.ts.map +1 -1
- package/dist/scraper/session-browserbase.js +29 -0
- package/dist/scraper/session-browserbase.js.map +1 -1
- package/dist/scraper/session-ip.d.ts +69 -0
- package/dist/scraper/session-ip.d.ts.map +1 -0
- package/dist/scraper/session-ip.js +88 -0
- package/dist/scraper/session-ip.js.map +1 -0
- package/dist/scraper/session-shared.d.ts +9 -0
- package/dist/scraper/session-shared.d.ts.map +1 -1
- package/dist/scraper/session-shared.js.map +1 -1
- package/dist/scraper/submit-control.d.ts +14 -2
- package/dist/scraper/submit-control.d.ts.map +1 -1
- package/dist/scraper/submit-control.js +33 -2
- package/dist/scraper/submit-control.js.map +1 -1
- package/dist/scripts/recon-browser.d.ts.map +1 -1
- package/dist/scripts/recon-browser.js +32 -0
- package/dist/scripts/recon-browser.js.map +1 -1
- package/dist/site-plugin.d.ts +20 -0
- package/dist/site-plugin.d.ts.map +1 -1
- package/dist/testing/integration-runner.d.ts.map +1 -1
- package/dist/testing/integration-runner.js +6 -7
- package/dist/testing/integration-runner.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -428,12 +428,48 @@ export const myPlugin: SitePlugin<MyPayload, MyResponse> = {
|
|
|
428
428
|
};
|
|
429
429
|
```
|
|
430
430
|
|
|
431
|
-
`dispatch()` (`src/plugins/loader.ts`) calls this once per submission
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
core never inspects its contents. A plugin with no reconciliation needs
|
|
431
|
+
`dispatch()` (`src/plugins/loader.ts`) calls this once per submission,
|
|
432
|
+
resolving `extractJoinKeys(payload)` from the inbound payload alone — core
|
|
433
|
+
never inspects the result's contents. A plugin with no reconciliation needs
|
|
435
434
|
simply omits `extractJoinKeys`.
|
|
436
435
|
|
|
436
|
+
#### Mid-run attach point (`context.telemetry.addJoinKeys`)
|
|
437
|
+
|
|
438
|
+
`extractJoinKeys` only ever sees the payload a plugin received up front, so
|
|
439
|
+
it has no way to attach a field the plugin only discovers *during* the run
|
|
440
|
+
— a token minted mid-flow, a value read from the page after navigation, a
|
|
441
|
+
value observed on a response. For that, call the mid-run attach point,
|
|
442
|
+
`context.telemetry.addJoinKeys()`, from anywhere inside `execute()` or
|
|
443
|
+
`executeHttp()`:
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
async execute(payload: MyPayload, session, context: SitePluginContext) {
|
|
447
|
+
const mintedToken = await readTokenFromPage(session);
|
|
448
|
+
context.telemetry.addJoinKeys({ mintedToken });
|
|
449
|
+
// ...
|
|
450
|
+
},
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
`context.telemetry` is a per-dispatch `RunTelemetry` accumulator
|
|
454
|
+
(`src/lib/telemetry/run-telemetry.ts`), constructed fresh for every
|
|
455
|
+
dispatch by `buildPluginContext` (`src/plugins/loader.ts`) alongside
|
|
456
|
+
`recordBeaconOutcome` below. Successive `addJoinKeys()` calls within the
|
|
457
|
+
same run merge, later calls winning on key collision. Once the plugin call
|
|
458
|
+
resolves — on both the success and error paths — `dispatch()` snapshots the
|
|
459
|
+
accumulator and merges it over the earlier `extractJoinKeys(payload)`
|
|
460
|
+
result, run-discovered keys winning on collision, before stamping the
|
|
461
|
+
combined bag onto the submission envelope's and beacon-fire record's
|
|
462
|
+
`joinKeys` field. `joinKeys` stays `null` only when neither source ever
|
|
463
|
+
produced anything.
|
|
464
|
+
|
|
465
|
+
**A config-only `*.plugin.json` manifest can reach
|
|
466
|
+
`context.telemetry.addJoinKeys()` only through the same `spec.httpModule`
|
|
467
|
+
escape hatch documented below for `context.recordBeaconOutcome`** —
|
|
468
|
+
`executeHttp(payload, context)` receives the same `SitePluginContext`, so an
|
|
469
|
+
`httpModule` can call it exactly like `execute()` does above; the
|
|
470
|
+
manifest's declarative browser flow cannot, since `runHealingFlow` is
|
|
471
|
+
data-driven with no imperative call site for either seam to live in.
|
|
472
|
+
|
|
437
473
|
**Declaring `extractJoinKeys` also opts the plugin out of core's automatic
|
|
438
474
|
`TrackingUrl` fire.** If the site returns a post-submission click-tracking
|
|
439
475
|
URL, declare it on the plugin's `bodySchema` by composing `JobTrackingSchema`
|
|
@@ -446,6 +482,63 @@ navs must share one browser session for a vendor's device-cookie
|
|
|
446
482
|
attribution to work) and skips its own fire — firing both would open two
|
|
447
483
|
independent sessions against the same URL.
|
|
448
484
|
|
|
485
|
+
By default a self-managing plugin's beacon-fire telemetry is stuck at
|
|
486
|
+
`beaconStatus: "skipped"`, since core has no visibility into a navigation the
|
|
487
|
+
plugin drives itself. To report the real outcome, call
|
|
488
|
+
`context.recordBeaconOutcome` — passed on `SitePluginContext` alongside
|
|
489
|
+
`baseUrl`/`logger`/`requestId`, bound to this run — from `execute()`,
|
|
490
|
+
`executeHttp()`, or an extra-route handler:
|
|
491
|
+
|
|
492
|
+
```ts
|
|
493
|
+
import type { SitePlugin, SitePluginContext } from "@enricai/barnacle/site-plugin";
|
|
494
|
+
|
|
495
|
+
export const myPlugin: SitePlugin<MyPayload, MyResponse> = {
|
|
496
|
+
extractJoinKeys: (payload) =>
|
|
497
|
+
payload.someVendorClickId ? { vendorClickId: payload.someVendorClickId } : null,
|
|
498
|
+
async execute(payload, session, context: SitePluginContext) {
|
|
499
|
+
const t0 = Date.now();
|
|
500
|
+
const fired = await runMySiteBeaconNav(session, payload.TrackingUrl);
|
|
501
|
+
await context.recordBeaconOutcome({
|
|
502
|
+
beaconStatus: fired ? "fired" : "failed",
|
|
503
|
+
joinKeys: { vendorClickId: payload.someVendorClickId },
|
|
504
|
+
trackingUrl: payload.TrackingUrl,
|
|
505
|
+
durationMs: Date.now() - t0,
|
|
506
|
+
});
|
|
507
|
+
// ...
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Core binds the run's `requestId` and the plugin's own `siteId` for you, so
|
|
513
|
+
`recordBeaconOutcome`'s input carries only `beaconStatus` (`"fired"` |
|
|
514
|
+
`"failed"` — `"skipped"` stays an engine-owned outcome), the opaque `joinKeys`
|
|
515
|
+
bag (same shape returned from `extractJoinKeys`), and optional `trackingUrl`/
|
|
516
|
+
`durationMs`. It never throws — a telemetry-sink hiccup cannot fail the
|
|
517
|
+
request. A `fired`/`failed` line recorded this way outranks the automatic
|
|
518
|
+
`skipped` line for the same `requestId` when the two are folded together
|
|
519
|
+
(see [Telemetry & LLM judging](docs/telemetry-and-judging.md)). A plugin that
|
|
520
|
+
never calls it keeps today's unchanged `skipped` default. Import
|
|
521
|
+
`BeaconOutcomeInput` from `@enricai/barnacle/site-plugin` if you want to type
|
|
522
|
+
the input object explicitly — that's the published subpath an out-of-tree
|
|
523
|
+
plugin resolves against its own `node_modules`; in-tree code under `src/`
|
|
524
|
+
uses the `@/site-plugin` alias instead.
|
|
525
|
+
|
|
526
|
+
**A config-only `*.plugin.json` manifest can reach `context.recordBeaconOutcome`
|
|
527
|
+
only through the `spec.httpModule` escape hatch** — `executeHttp(payload,
|
|
528
|
+
context)` receives the same `SitePluginContext` a module plugin's does, so an
|
|
529
|
+
`httpModule` can call it exactly like `execute()` does above. The manifest's
|
|
530
|
+
declarative browser flow cannot: `runHealingFlow` is data-driven, with no
|
|
531
|
+
imperative call site for a call like this to live in. One consequence to know
|
|
532
|
+
before adopting it: `buildConfigPlugin` never synthesizes `extractJoinKeys`,
|
|
533
|
+
so a config-only plugin is never `managesOwnTracking` — when the response
|
|
534
|
+
carries a `TrackingUrl`, core still fires it itself via `fireTrackingClick`,
|
|
535
|
+
and a manifest-recorded `fired`/`failed` line for that `requestId` ranks
|
|
536
|
+
equal to core's own line under `beaconRank()`, so the fold resolves by write
|
|
537
|
+
order (last line wins) rather than the manifest's line automatically
|
|
538
|
+
outranking core's. Only when no `TrackingUrl` is present — so core's own
|
|
539
|
+
write is the `skipped` default — does the manifest's recorded line
|
|
540
|
+
deterministically outrank it.
|
|
541
|
+
|
|
449
542
|
### Static fixtures
|
|
450
543
|
|
|
451
544
|
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:
|
|
@@ -670,17 +763,23 @@ in `src/lib/telemetry/reconciliation-record.ts`):
|
|
|
670
763
|
| `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
764
|
| `siteId` | `string` | Which plugin handled the request — the cohort dimension for reconciliation. |
|
|
672
765
|
| `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
|
|
766
|
+
| `joinKeys` | `Record<string, unknown> \| null` | Opaque, plugin-owned reconciliation join keys: the plugin's `extractJoinKeys` hook resolved once from the inbound payload, merged with anything the plugin attached mid-run via `context.telemetry.addJoinKeys()` (run-discovered keys win on collision — see [Reconciliation join keys](#reconciliation-join-keys-extractjoinkeys) above); `null` when neither source produced anything. |
|
|
674
767
|
| `inboundPayload` | `unknown` | The request body the caller posted, unredacted. |
|
|
675
768
|
| `status` | `"submitted" \| "error"` | Submit outcome. |
|
|
676
769
|
| `auditPayload` | `unknown` | The plugin's `SitePluginResult.auditPayload`, or `data` when absent; `null` on errors. |
|
|
677
770
|
| `errorMessage` | `string \| null` | Failure message on errors; `null` on success. |
|
|
678
771
|
| `durationMs` | `number` | Total dispatch wall time in milliseconds. |
|
|
679
772
|
| `ts` | `string` | ISO-8601 timestamp at write time. |
|
|
773
|
+
| `session` | `{ id, provider, ip, ipCapturedAt } \| null` | Identity and outbound IP of the Browserbase session that served this run; `null` on the direct-HTTP hot path where no session is ever acquired. See [Submission-envelope sink](docs/telemetry-and-judging.md#submission-envelope-sink) for capture details. |
|
|
680
774
|
|
|
681
775
|
A `"beacon"`-kind record shares the same sink to record a later, independent
|
|
682
|
-
beacon-fire outcome for the same `requestId
|
|
683
|
-
|
|
776
|
+
beacon-fire outcome for the same `requestId`. Core writes one itself — either
|
|
777
|
+
a `fired`/`failed` line once `fireTrackingClick` resolves, or a `skipped` line
|
|
778
|
+
when there is no `TrackingUrl` to fire or the plugin declared
|
|
779
|
+
`extractJoinKeys` — but a plugin managing its own tracking nav can also emit
|
|
780
|
+
one directly via `context.recordBeaconOutcome` (see
|
|
781
|
+
[Reconciliation join keys](#reconciliation-join-keys-extractjoinkeys) above).
|
|
782
|
+
See [Submission-envelope sink](docs/telemetry-and-judging.md#submission-envelope-sink)
|
|
684
783
|
for the full schema and the `GET /v1/submissions` read path.
|
|
685
784
|
|
|
686
785
|
#### Tailing call samples with jq
|
|
@@ -742,6 +841,10 @@ process to exit on missing values; optional ones have safe defaults.
|
|
|
742
841
|
| `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
842
|
| `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
843
|
| `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. |
|
|
844
|
+
| `FRAME_PRESENCE_PROBE_FLOOR_MS` | `3000` | No | Per-probe watchdog floor for `probeAttachedFrameTarget`'s single non-polling presence check (ms) — a real budget a genuine CDP round-trip can land within, instead of the `timeoutMs: 0` zero-budget pattern that always loses that race. |
|
|
845
|
+
| `SCRAPER_CAPTURE_SESSION_IP` | `true` | No | Master switch for the outbound-IP echo navigation; `false` yields `session: null` / `sessionIp: null` everywhere without touching the rest of the submit/beacon record. |
|
|
846
|
+
| `SCRAPER_SESSION_IP_ECHO_URL` | `https://api.ipify.org?format=json` | No | The IP-echo endpoint the session's own short-lived tab navigates to. Operators can point this at a self-hosted echo endpoint. |
|
|
847
|
+
| `SCRAPER_SESSION_IP_TIMEOUT_MS` | `10000` | No | Watchdog bound on the echo navigation; a page that never resolves is cut off and yields `null` rather than blocking the submission. |
|
|
745
848
|
|
|
746
849
|
### AWS Bedrock (alternative LLM provider)
|
|
747
850
|
|
|
@@ -823,7 +926,7 @@ http/net/dns. Metrics have no such constraint.
|
|
|
823
926
|
| `TELEMETRY_ENABLED` | `true` | Master switch — set `false` to disable all NDJSON telemetry writes. |
|
|
824
927
|
| `TELEMETRY_EVENTS_DIR` | `.barnacle/events` | Directory for per-run NDJSON event stream files (`<eventsDir>/<runId>.ndjson`). |
|
|
825
928
|
| `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. |
|
|
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`. |
|
|
929
|
+
| `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, merged with anything attached mid-run via `context.telemetry.addJoinKeys()` — 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 — the `skipped` line is always written by `dispatch()` itself, but a plugin managing its own tracking nav can call `context.recordBeaconOutcome` to append a real `fired`/`failed` line for the same `requestId`, which outranks `skipped` when the two are folded (see [Reconciliation join keys](#reconciliation-join-keys-extractjoinkeys)). 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`. |
|
|
827
930
|
| `TELEMETRY_MAX_FILE_SIZE_BYTES` | `104857600` (100 MB) | Rotate/drop the calls NDJSON once it exceeds this byte count. |
|
|
828
931
|
| `TELEMETRY_MAX_RETENTION_MS` | `2592000000` (30 days) | Drop event-stream files older than this many milliseconds. |
|
|
829
932
|
| `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). |
|
|
@@ -1017,7 +1120,7 @@ Operational routes:
|
|
|
1017
1120
|
- `GET /readyz` — readiness probe (checks scraper credentials, queue depth)
|
|
1018
1121
|
- `GET /docs` — Swagger UI (when `ENABLE_DOCS=true`)
|
|
1019
1122
|
- `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
|
|
1123
|
+
- `GET /v1/submissions` — authenticated, queryable submit+beacon reconciliation rows (filter by `siteId`, `requestId`, `status`, `beaconStatus`, `from`/`to`; each row also carries the submit session block `session` (`{ id, provider, ip, ipCapturedAt }`) and the beacon-fire `beaconSessionIp`, neither of which is filterable at this layer, same as the opaque `joinKeys` bag; see [Submission-envelope sink](docs/telemetry-and-judging.md#submission-envelope-sink))
|
|
1021
1124
|
|
|
1022
1125
|
## Commands
|
|
1023
1126
|
|
|
@@ -1077,6 +1180,7 @@ src/
|
|
|
1077
1180
|
│ ├── navigate.ts # shared awaitActivePage + goto(networkidle) helper
|
|
1078
1181
|
│ ├── behavioral-signals.ts # CDP synthetic mouse-move + scroll dispatcher for bot-detection warmup
|
|
1079
1182
|
│ ├── session-warmup.ts # generic pRetry browser-session runner: acquire → callback → close, with caller-supplied exhaustion mapping
|
|
1183
|
+
│ ├── session-ip.ts # resolves a session's outbound IP via a throwaway tab + IP-echo navigation
|
|
1080
1184
|
│ └── require-response-field.ts # shared helpers for extracting required fields from HTTP response objects (HttpSchemaError on missing/null)
|
|
1081
1185
|
├── cache/
|
|
1082
1186
|
│ ├── response-cache.ts # lru-cache wrapper for deduplicating concurrent identical scraper requests
|
|
@@ -44,6 +44,12 @@ export declare const reconciliationRowSchema: z.ZodObject<{
|
|
|
44
44
|
siteId: z.ZodString;
|
|
45
45
|
requestId: z.ZodString;
|
|
46
46
|
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
47
|
+
session: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
48
|
+
id: z.ZodString;
|
|
49
|
+
provider: z.ZodString;
|
|
50
|
+
ip: z.ZodNullable<z.ZodString>;
|
|
51
|
+
ipCapturedAt: z.ZodNullable<z.ZodString>;
|
|
52
|
+
}, z.core.$strip>>>;
|
|
47
53
|
status: z.ZodEnum<{
|
|
48
54
|
error: "error";
|
|
49
55
|
submitted: "submitted";
|
|
@@ -58,6 +64,7 @@ export declare const reconciliationRowSchema: z.ZodObject<{
|
|
|
58
64
|
skipped: "skipped";
|
|
59
65
|
}>;
|
|
60
66
|
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
67
|
+
beaconSessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
61
68
|
}, z.core.$strip>;
|
|
62
69
|
export type ReconciliationRow = z.infer<typeof reconciliationRowSchema>;
|
|
63
70
|
/**
|
|
@@ -89,6 +96,12 @@ export declare const submissionsResponseSchema: z.ZodObject<{
|
|
|
89
96
|
siteId: z.ZodString;
|
|
90
97
|
requestId: z.ZodString;
|
|
91
98
|
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
99
|
+
session: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
100
|
+
id: z.ZodString;
|
|
101
|
+
provider: z.ZodString;
|
|
102
|
+
ip: z.ZodNullable<z.ZodString>;
|
|
103
|
+
ipCapturedAt: z.ZodNullable<z.ZodString>;
|
|
104
|
+
}, z.core.$strip>>>;
|
|
92
105
|
status: z.ZodEnum<{
|
|
93
106
|
error: "error";
|
|
94
107
|
submitted: "submitted";
|
|
@@ -103,6 +116,7 @@ export declare const submissionsResponseSchema: z.ZodObject<{
|
|
|
103
116
|
skipped: "skipped";
|
|
104
117
|
}>;
|
|
105
118
|
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
119
|
+
beaconSessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
106
120
|
}, z.core.$strip>>;
|
|
107
121
|
total: z.ZodNumber;
|
|
108
122
|
}, z.core.$strip>;
|
|
@@ -1 +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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;iBAMhC,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"}
|
|
@@ -64,6 +64,7 @@ exports.reconciliationRowSchema = reconciliation_record_1.submitRecordSchema
|
|
|
64
64
|
.extend({
|
|
65
65
|
beaconStatus: reconciliationBeaconStatusSchema,
|
|
66
66
|
trackingUrl: v4_1.z.string().nullable(),
|
|
67
|
+
beaconSessionIp: reconciliation_record_1.beaconEventSchema.shape.sessionIp,
|
|
67
68
|
});
|
|
68
69
|
/**
|
|
69
70
|
* Response contract for the submissions read route: the standard envelope
|
|
@@ -1 +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;
|
|
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;IAClC,eAAe,EAAE,yCAAiB,CAAC,KAAK,CAAC,SAAS;CACnD,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
|
@@ -82,6 +82,39 @@ export interface AppConfig {
|
|
|
82
82
|
* racy OOPIF fails the attempt instead of hanging the step indefinitely.
|
|
83
83
|
*/
|
|
84
84
|
frameEvaluateTimeoutMs: number;
|
|
85
|
+
/**
|
|
86
|
+
* Per-probe watchdog floor for `probeAttachedFrameTarget`'s single
|
|
87
|
+
* non-polling presence check (`frame-target.ts`). That probe's deadline
|
|
88
|
+
* is `Date.now() + framePresenceProbeFloorMs`, not `Date.now() + 0` —
|
|
89
|
+
* `resolveFrameTarget(page, sel, { timeoutMs: 0 })`'s zero-budget pass
|
|
90
|
+
* clamps every probe to `Math.min(evaluateTimeoutMs, remainingBudgetMs())
|
|
91
|
+
* === 0`, so a `setTimeout(reject, 0)` macrotask always wins the race
|
|
92
|
+
* against a genuinely awaited CDP round-trip and the probe can never
|
|
93
|
+
* observe an already-attached frame in production. Kept well under
|
|
94
|
+
* `frameReadyTimeoutMs` since the probe never polls — at most two
|
|
95
|
+
* round-trips (the top-level iframe-src read plus one candidate
|
|
96
|
+
* `location.href` read, per `tryResolveChildFrame`'s existing
|
|
97
|
+
* `index > 0 && remainingBudgetMs() <= 0` bound) — so a single call costs
|
|
98
|
+
* at most ~2x this floor.
|
|
99
|
+
*/
|
|
100
|
+
framePresenceProbeFloorMs: number;
|
|
101
|
+
/**
|
|
102
|
+
* Master switch for the outbound-IP echo navigation. False yields
|
|
103
|
+
* `session: null` / `sessionIp: null` in the submit/beacon telemetry
|
|
104
|
+
* without disturbing the rest of the record.
|
|
105
|
+
*/
|
|
106
|
+
captureSessionIp: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* IP-echo endpoint the session's own short-lived tab navigates to.
|
|
109
|
+
* Overridable so operators can point this at a self-hosted echo
|
|
110
|
+
* endpoint instead of depending on a third party.
|
|
111
|
+
*/
|
|
112
|
+
sessionIpEchoUrl: string;
|
|
113
|
+
/**
|
|
114
|
+
* Watchdog bound on the echo navigation; a page that never resolves is
|
|
115
|
+
* cut off and yields `null` rather than blocking the submission.
|
|
116
|
+
*/
|
|
117
|
+
sessionIpTimeoutMs: number;
|
|
85
118
|
};
|
|
86
119
|
bedrock: {
|
|
87
120
|
region: string;
|
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;QAC9B;;;;;;WAMG;QACH,mBAAmB,EAAE,MAAM,CAAC;QAC5B;;;;;;WAMG;QACH,2BAA2B,EAAE,MAAM,CAAC;QACpC;;;;WAIG;QACH,sBAAsB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -70,6 +70,10 @@ function loadConfig() {
|
|
|
70
70
|
frameReadyTimeoutMs: (0, env_1.getNumericEnv)("FRAME_READY_TIMEOUT_MS", 20_000),
|
|
71
71
|
frameDocumentReadyTimeoutMs: (0, env_1.getNumericEnv)("FRAME_DOCUMENT_READY_TIMEOUT_MS", 5_000),
|
|
72
72
|
frameEvaluateTimeoutMs: (0, env_1.getNumericEnv)("FRAME_EVALUATE_TIMEOUT_MS", 30_000),
|
|
73
|
+
framePresenceProbeFloorMs: (0, env_1.getNumericEnv)("FRAME_PRESENCE_PROBE_FLOOR_MS", 3_000),
|
|
74
|
+
captureSessionIp: (0, env_1.getBoolEnv)("SCRAPER_CAPTURE_SESSION_IP", true),
|
|
75
|
+
sessionIpEchoUrl: (0, env_1.getEnv)("SCRAPER_SESSION_IP_ECHO_URL", "https://api.ipify.org?format=json"),
|
|
76
|
+
sessionIpTimeoutMs: (0, env_1.getNumericEnv)("SCRAPER_SESSION_IP_TIMEOUT_MS", 10_000),
|
|
73
77
|
},
|
|
74
78
|
bedrock: {
|
|
75
79
|
region: (0, env_1.getEnv)("AWS_REGION", "us-east-1"),
|
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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"}
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
* Writes to the SAME sink as submit lines (`appendSubmissionSinkLine`,
|
|
12
12
|
* feat-003), which is what lets the S3 mirror carry beacon lines for free
|
|
13
13
|
* with zero `s3-sink.ts` changes.
|
|
14
|
+
*
|
|
15
|
+
* `createBeaconOutcomeRecorder` builds on top of `captureBeaconEvent` to
|
|
16
|
+
* give a plugin that manages its own beacon navigation a bound, never-
|
|
17
|
+
* throwing way to report a real `fired`/`failed` outcome for its own run.
|
|
14
18
|
*/
|
|
15
19
|
import type { z } from "zod/v4";
|
|
16
20
|
import type { beaconEventSchema } from "../../lib/telemetry/reconciliation-record";
|
|
@@ -18,9 +22,13 @@ import type { beaconEventSchema } from "../../lib/telemetry/reconciliation-recor
|
|
|
18
22
|
export type BeaconEventSample = z.infer<typeof beaconEventSchema>;
|
|
19
23
|
/**
|
|
20
24
|
* Input to `captureBeaconEvent` — `ts` and `kind` are derived internally so
|
|
21
|
-
* callers omit them.
|
|
25
|
+
* callers omit them. `sessionIp` is optional so existing call sites that
|
|
26
|
+
* don't yet resolve it keep compiling unchanged; an omitted value is
|
|
27
|
+
* persisted as `null`, not left undefined.
|
|
22
28
|
*/
|
|
23
|
-
export type BeaconEventInput = Omit<BeaconEventSample, "ts" | "kind"
|
|
29
|
+
export type BeaconEventInput = Omit<BeaconEventSample, "ts" | "kind" | "sessionIp"> & {
|
|
30
|
+
sessionIp?: BeaconEventSample["sessionIp"];
|
|
31
|
+
};
|
|
24
32
|
/** Options for `captureBeaconEvent`. */
|
|
25
33
|
export interface CaptureBeaconEventOptions {
|
|
26
34
|
/** Override the sink path; used in tests to avoid touching the real file. */
|
|
@@ -34,4 +42,39 @@ export interface CaptureBeaconEventOptions {
|
|
|
34
42
|
* beacon caller (tracking-click) is already fire-and-forget.
|
|
35
43
|
*/
|
|
36
44
|
export declare function captureBeaconEvent(input: BeaconEventInput, opts?: CaptureBeaconEventOptions): Promise<void>;
|
|
45
|
+
/** A run's identity, bound once by `createBeaconOutcomeRecorder` so a plugin never supplies it itself. */
|
|
46
|
+
export interface BeaconOutcomeRecorderBinding {
|
|
47
|
+
requestId: string;
|
|
48
|
+
siteId: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Plugin-facing input to a bound beacon-outcome recorder — `requestId` and
|
|
52
|
+
* `siteId` are omitted (bound by the factory) and `beaconStatus` excludes
|
|
53
|
+
* `"skipped"`, which stays an engine-owned outcome written by `dispatch()`
|
|
54
|
+
* itself (see `loader.ts`'s `emitBeaconSafely` call). `trackingUrl` and
|
|
55
|
+
* `durationMs` are optional here (unlike `BeaconEventInput`) since a plugin
|
|
56
|
+
* managing its own nav may not have a URL or duration to report.
|
|
57
|
+
*/
|
|
58
|
+
export interface BeaconOutcomeInput {
|
|
59
|
+
beaconStatus: Extract<BeaconEventInput["beaconStatus"], "fired" | "failed">;
|
|
60
|
+
joinKeys: BeaconEventInput["joinKeys"];
|
|
61
|
+
trackingUrl?: BeaconEventInput["trackingUrl"];
|
|
62
|
+
durationMs?: BeaconEventInput["durationMs"];
|
|
63
|
+
}
|
|
64
|
+
/** A plugin-callable recorder bound to one run's `requestId`/`siteId`. */
|
|
65
|
+
export type BeaconOutcomeRecorder = (input: BeaconOutcomeInput, opts?: CaptureBeaconEventOptions) => Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Builds a plugin-callable recorder bound to a run's `requestId`/`siteId`,
|
|
68
|
+
* so a plugin that manages its own beacon navigation can report a real
|
|
69
|
+
* `fired`/`failed` outcome without touching `captureBeaconEvent`'s raw input
|
|
70
|
+
* shape or its `ts`/`kind` derivation — `joinKeys` is passed through
|
|
71
|
+
* uninterpreted, matching the opaque, plugin-owned shape precedent in
|
|
72
|
+
* `src/site-plugin.ts`. Wraps the delegated call in the same belt-and-braces
|
|
73
|
+
* try/catch every other beacon call site applies (`emitBeaconSafely` in
|
|
74
|
+
* `loader.ts`, `captureBeaconOutcomeSafely` in `tracking-click.ts`), so a
|
|
75
|
+
* synchronous throw that reaches `captureBeaconEvent` before its own
|
|
76
|
+
* internal try/catch opens can still never escape into the plugin's own
|
|
77
|
+
* execute path.
|
|
78
|
+
*/
|
|
79
|
+
export declare function createBeaconOutcomeRecorder(binding: BeaconOutcomeRecorderBinding): BeaconOutcomeRecorder;
|
|
37
80
|
//# sourceMappingURL=beacon-capture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beacon-capture.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"beacon-capture.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;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;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,iBAAiB,EAAE,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC,GAAG;IACpF,SAAS,CAAC,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;CAC5C,CAAC;AAEF,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,CAgBf;AAED,0GAA0G;AAC1G,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,CAAC;IAC5E,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAC9C,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;CAC7C;AAED,0EAA0E;AAC1E,MAAM,MAAM,qBAAqB,GAAG,CAClC,KAAK,EAAE,kBAAkB,EACzB,IAAI,CAAC,EAAE,yBAAyB,KAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,qBAAqB,CAkBvB"}
|
|
@@ -12,9 +12,14 @@
|
|
|
12
12
|
* Writes to the SAME sink as submit lines (`appendSubmissionSinkLine`,
|
|
13
13
|
* feat-003), which is what lets the S3 mirror carry beacon lines for free
|
|
14
14
|
* with zero `s3-sink.ts` changes.
|
|
15
|
+
*
|
|
16
|
+
* `createBeaconOutcomeRecorder` builds on top of `captureBeaconEvent` to
|
|
17
|
+
* give a plugin that manages its own beacon navigation a bound, never-
|
|
18
|
+
* throwing way to report a real `fired`/`failed` outcome for its own run.
|
|
15
19
|
*/
|
|
16
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
21
|
exports.captureBeaconEvent = captureBeaconEvent;
|
|
22
|
+
exports.createBeaconOutcomeRecorder = createBeaconOutcomeRecorder;
|
|
18
23
|
const date_fns_1 = require("date-fns");
|
|
19
24
|
const config_1 = require("../../config");
|
|
20
25
|
const logging_1 = require("../../lib/logging");
|
|
@@ -34,6 +39,7 @@ async function captureBeaconEvent(input, opts = {}) {
|
|
|
34
39
|
...input,
|
|
35
40
|
kind: "beacon",
|
|
36
41
|
trackingUrl: input.trackingUrl?.slice(0, TRACKING_URL_MAX_LENGTH) ?? null,
|
|
42
|
+
sessionIp: input.sessionIp ?? null,
|
|
37
43
|
ts: (0, date_fns_1.formatISO)(new Date()),
|
|
38
44
|
};
|
|
39
45
|
try {
|
|
@@ -44,4 +50,34 @@ async function captureBeaconEvent(input, opts = {}) {
|
|
|
44
50
|
logger.error(`captureBeaconEvent: failed to write to ${sinkPath}: ${String(err)}`);
|
|
45
51
|
}
|
|
46
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Builds a plugin-callable recorder bound to a run's `requestId`/`siteId`,
|
|
55
|
+
* so a plugin that manages its own beacon navigation can report a real
|
|
56
|
+
* `fired`/`failed` outcome without touching `captureBeaconEvent`'s raw input
|
|
57
|
+
* shape or its `ts`/`kind` derivation — `joinKeys` is passed through
|
|
58
|
+
* uninterpreted, matching the opaque, plugin-owned shape precedent in
|
|
59
|
+
* `src/site-plugin.ts`. Wraps the delegated call in the same belt-and-braces
|
|
60
|
+
* try/catch every other beacon call site applies (`emitBeaconSafely` in
|
|
61
|
+
* `loader.ts`, `captureBeaconOutcomeSafely` in `tracking-click.ts`), so a
|
|
62
|
+
* synchronous throw that reaches `captureBeaconEvent` before its own
|
|
63
|
+
* internal try/catch opens can still never escape into the plugin's own
|
|
64
|
+
* execute path.
|
|
65
|
+
*/
|
|
66
|
+
function createBeaconOutcomeRecorder(binding) {
|
|
67
|
+
return async (input, opts = {}) => {
|
|
68
|
+
try {
|
|
69
|
+
await captureBeaconEvent({
|
|
70
|
+
requestId: binding.requestId,
|
|
71
|
+
siteId: binding.siteId,
|
|
72
|
+
joinKeys: input.joinKeys,
|
|
73
|
+
beaconStatus: input.beaconStatus,
|
|
74
|
+
trackingUrl: input.trackingUrl ?? null,
|
|
75
|
+
durationMs: input.durationMs ?? 0,
|
|
76
|
+
}, opts);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
logger.error(`createBeaconOutcomeRecorder: capture failed: ${String(err)}`);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
47
83
|
//# sourceMappingURL=beacon-capture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beacon-capture.js","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"beacon-capture.js","sourceRoot":"","sources":["../../../src/lib/telemetry/beacon-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;;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;AAqBpC;;;;;;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,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAClC,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;AA6BD;;;;;;;;;;;;GAYG;AACH,qCACE,OAAqC;IAErC,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,kBAAkB,CACtB;gBACE,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;gBACtC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,CAAC;aAClC,EACD,IAAI,CACL,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,gDAAgD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -17,8 +17,37 @@
|
|
|
17
17
|
* `kind` defaults to `"submit"` because `.barnacle/submissions.ndjson`
|
|
18
18
|
* already holds historical unkinded lines that `s3-sink.ts` has shipped to
|
|
19
19
|
* S3 — a required `kind` would make every one of those lines unparseable.
|
|
20
|
+
*
|
|
21
|
+
* `reconciliationRecordSchema`'s preprocess step also folds a legacy
|
|
22
|
+
* top-level `vivclid`/`jobReference` shape into `joinKeys`: before the
|
|
23
|
+
* opaque `joinKeys` bag existed, those two fields were persisted as named
|
|
24
|
+
* top-level keys, and a plain `z.object()` silently drops unrecognized
|
|
25
|
+
* keys — reading an old line through the new schema would otherwise lose
|
|
26
|
+
* its join keys rather than surface them.
|
|
27
|
+
*
|
|
28
|
+
* `session` (on `submitRecordSchema`) and `sessionIp` (on `beaconEventSchema`)
|
|
29
|
+
* carry the Browserbase session's identity and outbound IP so it's durable
|
|
30
|
+
* per-run telemetry rather than only a log line — every plugin acquires its
|
|
31
|
+
* session the same engine-owned way, so this lands here rather than
|
|
32
|
+
* per-plugin. Both are nullable-with-default for the same reason `joinKeys`
|
|
33
|
+
* is: millions of already-shipped NDJSON lines (and their S3 mirror) never
|
|
34
|
+
* carried these fields and must keep parsing.
|
|
20
35
|
*/
|
|
21
36
|
import { z } from "zod/v4";
|
|
37
|
+
/**
|
|
38
|
+
* The Browserbase session identity and outbound IP a plugin's run used.
|
|
39
|
+
* `ip`/`ipCapturedAt` are nullable independently of `id`/`provider` because
|
|
40
|
+
* the IP is only known after a separate in-session IP-echo navigation, which
|
|
41
|
+
* may never resolve (a disabled capture, a provider with no IP accessor, a
|
|
42
|
+
* timeout) even when the session itself was acquired successfully.
|
|
43
|
+
*/
|
|
44
|
+
export declare const sessionTelemetrySchema: z.ZodObject<{
|
|
45
|
+
id: z.ZodString;
|
|
46
|
+
provider: z.ZodString;
|
|
47
|
+
ip: z.ZodNullable<z.ZodString>;
|
|
48
|
+
ipCapturedAt: z.ZodNullable<z.ZodString>;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
export type SessionTelemetry = z.infer<typeof sessionTelemetrySchema>;
|
|
22
51
|
/**
|
|
23
52
|
* Submit-side record: the existing submission envelope shape plus an opaque
|
|
24
53
|
* `joinKeys` bag. Nullable-with-default so pre-existing lines that never
|
|
@@ -29,6 +58,12 @@ export declare const submitRecordSchema: z.ZodObject<{
|
|
|
29
58
|
siteId: z.ZodString;
|
|
30
59
|
requestId: z.ZodString;
|
|
31
60
|
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
61
|
+
session: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
62
|
+
id: z.ZodString;
|
|
63
|
+
provider: z.ZodString;
|
|
64
|
+
ip: z.ZodNullable<z.ZodString>;
|
|
65
|
+
ipCapturedAt: z.ZodNullable<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>>>;
|
|
32
67
|
inboundPayload: z.ZodUnknown;
|
|
33
68
|
status: z.ZodEnum<{
|
|
34
69
|
error: "error";
|
|
@@ -49,7 +84,11 @@ export type SubmitRecord = z.infer<typeof submitRecordSchema>;
|
|
|
49
84
|
* `dispatch()` in `src/plugins/loader.ts`) — distinct from `"not_fired"`
|
|
50
85
|
* (the reader's fold default for a submit row with no matching beacon line
|
|
51
86
|
* at all), so "submitted but the beacon did not fire" excludes runs that
|
|
52
|
-
* never had a beacon to fire.
|
|
87
|
+
* never had a beacon to fire. `"skipped"` is not necessarily terminal for a
|
|
88
|
+
* self-managing plugin: if that plugin later records its own real `fired`/
|
|
89
|
+
* `failed` line for the same `requestId`, `foldReconciliationRecords` in
|
|
90
|
+
* `submission-reader.ts` ranks the real outcome above `"skipped"` and folds
|
|
91
|
+
* to that outcome regardless of which line was written first.
|
|
53
92
|
*/
|
|
54
93
|
export declare const beaconEventSchema: z.ZodObject<{
|
|
55
94
|
kind: z.ZodLiteral<"beacon">;
|
|
@@ -64,6 +103,7 @@ export declare const beaconEventSchema: z.ZodObject<{
|
|
|
64
103
|
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
65
104
|
durationMs: z.ZodNumber;
|
|
66
105
|
ts: z.ZodString;
|
|
106
|
+
sessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
67
107
|
}, z.core.$strip>;
|
|
68
108
|
export type BeaconEvent = z.infer<typeof beaconEventSchema>;
|
|
69
109
|
/**
|
|
@@ -71,13 +111,20 @@ export type BeaconEvent = z.infer<typeof beaconEventSchema>;
|
|
|
71
111
|
* `kind`. Injects `kind: "submit"` ahead of the discriminated union when the
|
|
72
112
|
* field is absent, because `z.discriminatedUnion` reads the raw input's
|
|
73
113
|
* discriminant directly and won't fall back to a member schema's default —
|
|
74
|
-
* confirmed against zod/v4 3.25.76.
|
|
114
|
+
* confirmed against zod/v4 3.25.76. Also folds a legacy vivclid/jobReference
|
|
115
|
+
* shape into `joinKeys` (see `withLegacyJoinKeys`) before the union runs.
|
|
75
116
|
*/
|
|
76
117
|
export declare const reconciliationRecordSchema: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
77
118
|
kind: z.ZodDefault<z.ZodLiteral<"submit">>;
|
|
78
119
|
siteId: z.ZodString;
|
|
79
120
|
requestId: z.ZodString;
|
|
80
121
|
joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
122
|
+
session: z.ZodDefault<z.ZodNullable<z.ZodObject<{
|
|
123
|
+
id: z.ZodString;
|
|
124
|
+
provider: z.ZodString;
|
|
125
|
+
ip: z.ZodNullable<z.ZodString>;
|
|
126
|
+
ipCapturedAt: z.ZodNullable<z.ZodString>;
|
|
127
|
+
}, z.core.$strip>>>;
|
|
81
128
|
inboundPayload: z.ZodUnknown;
|
|
82
129
|
status: z.ZodEnum<{
|
|
83
130
|
error: "error";
|
|
@@ -100,6 +147,7 @@ export declare const reconciliationRecordSchema: z.ZodPipe<z.ZodTransform<unknow
|
|
|
100
147
|
trackingUrl: z.ZodNullable<z.ZodString>;
|
|
101
148
|
durationMs: z.ZodNumber;
|
|
102
149
|
ts: z.ZodString;
|
|
150
|
+
sessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
103
151
|
}, z.core.$strip>]>>;
|
|
104
152
|
export type ReconciliationRecord = z.infer<typeof reconciliationRecordSchema>;
|
|
105
153
|
//# sourceMappingURL=reconciliation-record.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciliation-record.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-record.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reconciliation-record.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB;;;;;iBAKjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;iBAU5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAsB5D;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAOtC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|