@enricai/barnacle 1.6.12 → 1.6.14

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.
Files changed (108) hide show
  1. package/README.md +113 -9
  2. package/dist/api/schemas/submissions.d.ts +14 -0
  3. package/dist/api/schemas/submissions.d.ts.map +1 -1
  4. package/dist/api/schemas/submissions.js +1 -0
  5. package/dist/api/schemas/submissions.js.map +1 -1
  6. package/dist/config.d.ts +33 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +4 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/lib/bedrock.d.ts +8 -5
  11. package/dist/lib/bedrock.d.ts.map +1 -1
  12. package/dist/lib/bedrock.js +8 -5
  13. package/dist/lib/bedrock.js.map +1 -1
  14. package/dist/lib/http.d.ts +4 -3
  15. package/dist/lib/http.d.ts.map +1 -1
  16. package/dist/lib/http.js +25 -3
  17. package/dist/lib/http.js.map +1 -1
  18. package/dist/lib/telemetry/beacon-capture.d.ts +45 -2
  19. package/dist/lib/telemetry/beacon-capture.d.ts.map +1 -1
  20. package/dist/lib/telemetry/beacon-capture.js +36 -0
  21. package/dist/lib/telemetry/beacon-capture.js.map +1 -1
  22. package/dist/lib/telemetry/reconciliation-record.d.ts +41 -1
  23. package/dist/lib/telemetry/reconciliation-record.d.ts.map +1 -1
  24. package/dist/lib/telemetry/reconciliation-record.js +29 -2
  25. package/dist/lib/telemetry/reconciliation-record.js.map +1 -1
  26. package/dist/lib/telemetry/reconciliation-source.d.ts +7 -1
  27. package/dist/lib/telemetry/reconciliation-source.d.ts.map +1 -1
  28. package/dist/lib/telemetry/reconciliation-source.js +21 -5
  29. package/dist/lib/telemetry/reconciliation-source.js.map +1 -1
  30. package/dist/lib/telemetry/run-telemetry.d.ts +67 -0
  31. package/dist/lib/telemetry/run-telemetry.d.ts.map +1 -0
  32. package/dist/lib/telemetry/run-telemetry.js +55 -0
  33. package/dist/lib/telemetry/run-telemetry.js.map +1 -0
  34. package/dist/lib/telemetry/submission-capture.d.ts +11 -4
  35. package/dist/lib/telemetry/submission-capture.d.ts.map +1 -1
  36. package/dist/lib/telemetry/submission-capture.js +1 -0
  37. package/dist/lib/telemetry/submission-capture.js.map +1 -1
  38. package/dist/lib/telemetry/submission-reader.d.ts +11 -3
  39. package/dist/lib/telemetry/submission-reader.d.ts.map +1 -1
  40. package/dist/lib/telemetry/submission-reader.js +32 -8
  41. package/dist/lib/telemetry/submission-reader.js.map +1 -1
  42. package/dist/lib/tracking-click.d.ts.map +1 -1
  43. package/dist/lib/tracking-click.js +19 -0
  44. package/dist/lib/tracking-click.js.map +1 -1
  45. package/dist/plugins/config-plugin.js +3 -3
  46. package/dist/plugins/loader.d.ts +20 -0
  47. package/dist/plugins/loader.d.ts.map +1 -1
  48. package/dist/plugins/loader.js +94 -17
  49. package/dist/plugins/loader.js.map +1 -1
  50. package/dist/scraper/deep-locator-actuate.d.ts +94 -0
  51. package/dist/scraper/deep-locator-actuate.d.ts.map +1 -0
  52. package/dist/scraper/deep-locator-actuate.js +216 -0
  53. package/dist/scraper/deep-locator-actuate.js.map +1 -0
  54. package/dist/scraper/deep-locator-candidates.d.ts +105 -18
  55. package/dist/scraper/deep-locator-candidates.d.ts.map +1 -1
  56. package/dist/scraper/deep-locator-candidates.js +238 -46
  57. package/dist/scraper/deep-locator-candidates.js.map +1 -1
  58. package/dist/scraper/deep-locator-click.d.ts +71 -0
  59. package/dist/scraper/deep-locator-click.d.ts.map +1 -0
  60. package/dist/scraper/deep-locator-click.js +71 -0
  61. package/dist/scraper/deep-locator-click.js.map +1 -0
  62. package/dist/scraper/deep-locator-fake.d.ts +344 -14
  63. package/dist/scraper/deep-locator-fake.d.ts.map +1 -1
  64. package/dist/scraper/deep-locator-fake.js +509 -7
  65. package/dist/scraper/deep-locator-fake.js.map +1 -1
  66. package/dist/scraper/deep-locator-scan.d.ts +220 -0
  67. package/dist/scraper/deep-locator-scan.d.ts.map +1 -0
  68. package/dist/scraper/deep-locator-scan.js +386 -0
  69. package/dist/scraper/deep-locator-scan.js.map +1 -0
  70. package/dist/scraper/fake-timer-advance.d.ts +47 -0
  71. package/dist/scraper/fake-timer-advance.d.ts.map +1 -0
  72. package/dist/scraper/fake-timer-advance.js +44 -0
  73. package/dist/scraper/fake-timer-advance.js.map +1 -0
  74. package/dist/scraper/flow-runner.d.ts +80 -9
  75. package/dist/scraper/flow-runner.d.ts.map +1 -1
  76. package/dist/scraper/flow-runner.js +417 -63
  77. package/dist/scraper/flow-runner.js.map +1 -1
  78. package/dist/scraper/frame-target.d.ts +28 -0
  79. package/dist/scraper/frame-target.d.ts.map +1 -1
  80. package/dist/scraper/frame-target.js +30 -0
  81. package/dist/scraper/frame-target.js.map +1 -1
  82. package/dist/scraper/session-browserbase.d.ts +13 -0
  83. package/dist/scraper/session-browserbase.d.ts.map +1 -1
  84. package/dist/scraper/session-browserbase.js +29 -0
  85. package/dist/scraper/session-browserbase.js.map +1 -1
  86. package/dist/scraper/session-ip.d.ts +69 -0
  87. package/dist/scraper/session-ip.d.ts.map +1 -0
  88. package/dist/scraper/session-ip.js +88 -0
  89. package/dist/scraper/session-ip.js.map +1 -0
  90. package/dist/scraper/session-shared.d.ts +9 -0
  91. package/dist/scraper/session-shared.d.ts.map +1 -1
  92. package/dist/scraper/session-shared.js.map +1 -1
  93. package/dist/scraper/submit-control.d.ts +14 -2
  94. package/dist/scraper/submit-control.d.ts.map +1 -1
  95. package/dist/scraper/submit-control.js +33 -2
  96. package/dist/scraper/submit-control.js.map +1 -1
  97. package/dist/scripts/recon-browser.d.ts +1 -1
  98. package/dist/scripts/recon-browser.d.ts.map +1 -1
  99. package/dist/scripts/recon-browser.js +48 -16
  100. package/dist/scripts/recon-browser.js.map +1 -1
  101. package/dist/scripts/recon-generate.js +3 -3
  102. package/dist/scripts/recon-generate.js.map +1 -1
  103. package/dist/site-plugin.d.ts +20 -0
  104. package/dist/site-plugin.d.ts.map +1 -1
  105. package/dist/testing/integration-runner.d.ts.map +1 -1
  106. package/dist/testing/integration-runner.js +6 -7
  107. package/dist/testing/integration-runner.js.map +1 -1
  108. package/package.json +3 -2
@@ -1 +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"}
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"}
@@ -24,8 +24,30 @@
24
24
  * top-level keys, and a plain `z.object()` silently drops unrecognized
25
25
  * keys — reading an old line through the new schema would otherwise lose
26
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.
27
35
  */
28
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>;
29
51
  /**
30
52
  * Submit-side record: the existing submission envelope shape plus an opaque
31
53
  * `joinKeys` bag. Nullable-with-default so pre-existing lines that never
@@ -36,6 +58,12 @@ export declare const submitRecordSchema: z.ZodObject<{
36
58
  siteId: z.ZodString;
37
59
  requestId: z.ZodString;
38
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>>>;
39
67
  inboundPayload: z.ZodUnknown;
40
68
  status: z.ZodEnum<{
41
69
  error: "error";
@@ -56,7 +84,11 @@ export type SubmitRecord = z.infer<typeof submitRecordSchema>;
56
84
  * `dispatch()` in `src/plugins/loader.ts`) — distinct from `"not_fired"`
57
85
  * (the reader's fold default for a submit row with no matching beacon line
58
86
  * at all), so "submitted but the beacon did not fire" excludes runs that
59
- * 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.
60
92
  */
61
93
  export declare const beaconEventSchema: z.ZodObject<{
62
94
  kind: z.ZodLiteral<"beacon">;
@@ -71,6 +103,7 @@ export declare const beaconEventSchema: z.ZodObject<{
71
103
  trackingUrl: z.ZodNullable<z.ZodString>;
72
104
  durationMs: z.ZodNumber;
73
105
  ts: z.ZodString;
106
+ sessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
74
107
  }, z.core.$strip>;
75
108
  export type BeaconEvent = z.infer<typeof beaconEventSchema>;
76
109
  /**
@@ -86,6 +119,12 @@ export declare const reconciliationRecordSchema: z.ZodPipe<z.ZodTransform<unknow
86
119
  siteId: z.ZodString;
87
120
  requestId: z.ZodString;
88
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>>>;
89
128
  inboundPayload: z.ZodUnknown;
90
129
  status: z.ZodEnum<{
91
130
  error: "error";
@@ -108,6 +147,7 @@ export declare const reconciliationRecordSchema: z.ZodPipe<z.ZodTransform<unknow
108
147
  trackingUrl: z.ZodNullable<z.ZodString>;
109
148
  durationMs: z.ZodNumber;
110
149
  ts: z.ZodString;
150
+ sessionIp: z.ZodDefault<z.ZodNullable<z.ZodString>>;
111
151
  }, z.core.$strip>]>>;
112
152
  export type ReconciliationRecord = z.infer<typeof reconciliationRecordSchema>;
113
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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAE3B;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;iBAW7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;iBAS5B,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"}
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"}
@@ -25,10 +25,31 @@
25
25
  * top-level keys, and a plain `z.object()` silently drops unrecognized
26
26
  * keys — reading an old line through the new schema would otherwise lose
27
27
  * its join keys rather than surface them.
28
+ *
29
+ * `session` (on `submitRecordSchema`) and `sessionIp` (on `beaconEventSchema`)
30
+ * carry the Browserbase session's identity and outbound IP so it's durable
31
+ * per-run telemetry rather than only a log line — every plugin acquires its
32
+ * session the same engine-owned way, so this lands here rather than
33
+ * per-plugin. Both are nullable-with-default for the same reason `joinKeys`
34
+ * is: millions of already-shipped NDJSON lines (and their S3 mirror) never
35
+ * carried these fields and must keep parsing.
28
36
  */
29
37
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.reconciliationRecordSchema = exports.beaconEventSchema = exports.submitRecordSchema = void 0;
38
+ exports.reconciliationRecordSchema = exports.beaconEventSchema = exports.submitRecordSchema = exports.sessionTelemetrySchema = void 0;
31
39
  const v4_1 = require("zod/v4");
40
+ /**
41
+ * The Browserbase session identity and outbound IP a plugin's run used.
42
+ * `ip`/`ipCapturedAt` are nullable independently of `id`/`provider` because
43
+ * the IP is only known after a separate in-session IP-echo navigation, which
44
+ * may never resolve (a disabled capture, a provider with no IP accessor, a
45
+ * timeout) even when the session itself was acquired successfully.
46
+ */
47
+ exports.sessionTelemetrySchema = v4_1.z.object({
48
+ id: v4_1.z.string(),
49
+ provider: v4_1.z.string(),
50
+ ip: v4_1.z.string().nullable(),
51
+ ipCapturedAt: v4_1.z.string().nullable(),
52
+ });
32
53
  /**
33
54
  * Submit-side record: the existing submission envelope shape plus an opaque
34
55
  * `joinKeys` bag. Nullable-with-default so pre-existing lines that never
@@ -39,6 +60,7 @@ exports.submitRecordSchema = v4_1.z.object({
39
60
  siteId: v4_1.z.string(),
40
61
  requestId: v4_1.z.string(),
41
62
  joinKeys: v4_1.z.record(v4_1.z.string(), v4_1.z.unknown()).nullable().default(null),
63
+ session: exports.sessionTelemetrySchema.nullable().default(null),
42
64
  inboundPayload: v4_1.z.unknown(),
43
65
  status: v4_1.z.enum(["submitted", "error"]),
44
66
  auditPayload: v4_1.z.unknown(),
@@ -55,7 +77,11 @@ exports.submitRecordSchema = v4_1.z.object({
55
77
  * `dispatch()` in `src/plugins/loader.ts`) — distinct from `"not_fired"`
56
78
  * (the reader's fold default for a submit row with no matching beacon line
57
79
  * at all), so "submitted but the beacon did not fire" excludes runs that
58
- * never had a beacon to fire.
80
+ * never had a beacon to fire. `"skipped"` is not necessarily terminal for a
81
+ * self-managing plugin: if that plugin later records its own real `fired`/
82
+ * `failed` line for the same `requestId`, `foldReconciliationRecords` in
83
+ * `submission-reader.ts` ranks the real outcome above `"skipped"` and folds
84
+ * to that outcome regardless of which line was written first.
59
85
  */
60
86
  exports.beaconEventSchema = v4_1.z.object({
61
87
  kind: v4_1.z.literal("beacon"),
@@ -66,6 +92,7 @@ exports.beaconEventSchema = v4_1.z.object({
66
92
  trackingUrl: v4_1.z.string().nullable(),
67
93
  durationMs: v4_1.z.number(),
68
94
  ts: v4_1.z.string(),
95
+ sessionIp: v4_1.z.string().nullable().default(null),
69
96
  });
70
97
  /**
71
98
  * Folds a legacy top-level `vivclid`/`jobReference` shape into `joinKeys`
@@ -1 +1 @@
1
- {"version":3,"file":"reconciliation-record.js","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-record.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;AAEH,+BAA2B;AAE3B;;;;GAIG;AACU,QAAA,kBAAkB,GAAG,MAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,MAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC3C,MAAM,EAAE,MAAC,CAAC,MAAM,EAAE;IAClB,SAAS,EAAE,MAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,MAAC,CAAC,MAAM,CAAC,MAAC,CAAC,MAAM,EAAE,EAAE,MAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACpE,cAAc,EAAE,MAAC,CAAC,OAAO,EAAE;IAC3B,MAAM,EAAE,MAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACtC,YAAY,EAAE,MAAC,CAAC,OAAO,EAAE;IACzB,YAAY,EAAE,MAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,MAAC,CAAC,MAAM,EAAE;IACtB,EAAE,EAAE,MAAC,CAAC,MAAM,EAAE;CACf,CAAC,CAAC;AAIH;;;;;;;;;;GAUG;AACU,QAAA,iBAAiB,GAAG,MAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,MAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,SAAS,EAAE,MAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,MAAC,CAAC,MAAM,EAAE;IAClB,QAAQ,EAAE,MAAC,CAAC,MAAM,CAAC,MAAC,CAAC,MAAM,EAAE,EAAE,MAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtD,YAAY,EAAE,MAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpD,WAAW,EAAE,MAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,MAAC,CAAC,MAAM,EAAE;IACtB,EAAE,EAAE,MAAC,CAAC,MAAM,EAAE;CACf,CAAC,CAAC;AAIH;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,KAA8B;IACxD,IAAI,UAAU,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACjD,MAAM,cAAc,GAClB,OAAO,IAAI,YAAY;QACrB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,YAAY,EAAE,YAAY,IAAI,IAAI,EAAE;QAClE,CAAC,CAAC,IAAI,CAAC;IACX,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACU,QAAA,0BAA0B,GAAG,MAAC,CAAC,UAAU,CACpD,CAAC,KAAK,EAAE,EAAE;IACR,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACxE,OAAO,kBAAkB,CAAC,QAAmC,CAAC,CAAC;AACjE,CAAC,EACD,MAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,QAAA,kBAAkB,EAAE,QAAA,iBAAiB,CAAC,CAAC,CACtE,CAAC"}
1
+ {"version":3,"file":"reconciliation-record.js","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-record.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,13 @@
13
13
  * every event (`appendSubmissionSinkLine` writes to disk and buffers to S3
14
14
  * in the same call), so an overlap between the two stores is an exact JSON
15
15
  * duplicate, never a conflicting value — deduping on `kind:requestId:ts` is
16
- * therefore lossless.
16
+ * lossless for that mirror case. But `ts` is formatISO second-precision, so
17
+ * two *distinct* beacon lines for the same `requestId` (e.g. dispatch's
18
+ * automatic `skipped` line and a plugin's later self-recorded `fired` line)
19
+ * can land in the same wall-clock second — the dedupe key for beacon
20
+ * records also folds in `beaconStatus` and `trackingUrl` so non-identical
21
+ * beacon outcomes never collide, while submit records keep the plain
22
+ * `kind:requestId:ts` key.
17
23
  */
18
24
  import { type ReconciliationRow } from "../../lib/telemetry/submission-reader";
19
25
  import { type ListSubmissionsS3ObjectsOptions } from "../../lib/telemetry/submissions-s3-objects";
@@ -1 +1 @@
1
- {"version":3,"file":"reconciliation-source.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,KAAK,+BAA+B,EAErC,MAAM,wCAAwC,CAAC;AAKhD,mDAAmD;AACnD,MAAM,WAAW,oCAAqC,SAAQ,+BAA+B;IAC3F,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAwDD;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,GAAE,oCAAyC,GAC9C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAS9B"}
1
+ {"version":3,"file":"reconciliation-source.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AASH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,KAAK,+BAA+B,EAErC,MAAM,wCAAwC,CAAC;AAKhD,mDAAmD;AACnD,MAAM,WAAW,oCAAqC,SAAQ,+BAA+B;IAC3F,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkED;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,GAAE,oCAAyC,GAC9C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAS9B"}
@@ -14,7 +14,13 @@
14
14
  * every event (`appendSubmissionSinkLine` writes to disk and buffers to S3
15
15
  * in the same call), so an overlap between the two stores is an exact JSON
16
16
  * duplicate, never a conflicting value — deduping on `kind:requestId:ts` is
17
- * therefore lossless.
17
+ * lossless for that mirror case. But `ts` is formatISO second-precision, so
18
+ * two *distinct* beacon lines for the same `requestId` (e.g. dispatch's
19
+ * automatic `skipped` line and a plugin's later self-recorded `fired` line)
20
+ * can land in the same wall-clock second — the dedupe key for beacon
21
+ * records also folds in `beaconStatus` and `trackingUrl` so non-identical
22
+ * beacon outcomes never collide, while submit records keep the plain
23
+ * `kind:requestId:ts` key.
18
24
  */
19
25
  Object.defineProperty(exports, "__esModule", { value: true });
20
26
  exports.readDurableReconciliationRows = readDurableReconciliationRows;
@@ -57,14 +63,24 @@ async function readS3Records(opts) {
57
63
  return [];
58
64
  }
59
65
  }
60
- /** Dedupe key for a raw record: the same line written to both stores collapses to one. */
66
+ /**
67
+ * Dedupe key for a raw record: the same line written to both stores
68
+ * collapses to one. Beacon records also key on `beaconStatus` and
69
+ * `trackingUrl` — `ts` alone is second-precision, so a `skipped` line and a
70
+ * later `fired`/`failed` line for the same `requestId` can share a `ts` and
71
+ * must not be treated as the same line.
72
+ */
61
73
  function dedupeKey(record) {
74
+ if (record.kind === "beacon") {
75
+ return `${record.kind}:${record.requestId}:${record.ts}:${record.beaconStatus}:${record.trackingUrl ?? ""}`;
76
+ }
62
77
  return `${record.kind}:${record.requestId}:${record.ts}`;
63
78
  }
64
79
  /**
65
- * Unions the two record sets, local first, and dedupes on
66
- * `kind:requestId:ts` — the same line written to both stores collapses to
67
- * one entry, so `foldReconciliationRecords` sees it exactly once.
80
+ * Unions the two record sets, local first, and dedupes with `dedupeKey` —
81
+ * the same line written to both stores collapses to one entry, so
82
+ * `foldReconciliationRecords` sees it exactly once, while distinct beacon
83
+ * outcomes sharing a `requestId`/`ts` both survive.
68
84
  */
69
85
  function mergeRecords(localRecords, s3Records) {
70
86
  const deduped = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"reconciliation-source.js","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-source.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;AAEH,qCAAqC;AACrC,+CAA4C;AAE5C,qCAAkC;AAClC,yCAA8C;AAC9C,2CAA0C;AAE1C,yEAI2C;AAC3C,mFAGgD;AAChD,iFAAkF;AAElF,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,CAAC,CAAC;AAQtE;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IAC9C,IAAI,CAAC,IAAA,oBAAU,EAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,IAAA,4CAAwB,EAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAC1B,IAAqC;IAErC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,iDAAwB,EAAC,IAAI,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACjC,OAAO,MAAM,IAAA,iDAAyB,EAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,2EAA2E,IAAA,uBAAc,EAAC,GAAG,CAAC,EAAE,CACjG,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,SAAS,SAAS,CAAC,MAA4B;IAC7C,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CACnB,YAAoC,EACpC,SAAiC;IAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IACxD,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,YAAY,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACI,KAAK,wCACV,IAAI,GAAyC,EAAE;IAE/C,MAAM,EAAE,QAAQ,GAAG,eAAM,CAAC,SAAS,CAAC,qBAAqB,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAElF,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,gBAAgB,CAAC,QAAQ,CAAC;QAC1B,aAAa,CAAC,UAAU,CAAC;KAC1B,CAAC,CAAC;IAEH,OAAO,IAAA,6CAAyB,EAAC,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1E,CAAC"}
1
+ {"version":3,"file":"reconciliation-source.js","sourceRoot":"","sources":["../../../src/lib/telemetry/reconciliation-source.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAEH,qCAAqC;AACrC,+CAA4C;AAE5C,qCAAkC;AAClC,yCAA8C;AAC9C,2CAA0C;AAE1C,yEAI2C;AAC3C,mFAGgD;AAChD,iFAAkF;AAElF,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,iCAAiC,EAAE,CAAC,CAAC;AAQtE;;;;;GAKG;AACH,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IAC9C,IAAI,CAAC,IAAA,oBAAU,EAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,IAAA,mBAAQ,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,IAAA,4CAAwB,EAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAC1B,IAAqC;IAErC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,iDAAwB,EAAC,IAAI,CAAC,CAAC;QAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACjC,OAAO,MAAM,IAAA,iDAAyB,EAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,2EAA2E,IAAA,uBAAc,EAAC,GAAG,CAAC,EAAE,CACjG,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,SAAS,CAAC,MAA4B;IAC7C,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;IAC9G,CAAC;IACD,OAAO,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CACnB,YAAoC,EACpC,SAAiC;IAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IACxD,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,YAAY,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACI,KAAK,wCACV,IAAI,GAAyC,EAAE;IAE/C,MAAM,EAAE,QAAQ,GAAG,eAAM,CAAC,SAAS,CAAC,qBAAqB,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAElF,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,gBAAgB,CAAC,QAAQ,CAAC;QAC1B,aAAa,CAAC,UAAU,CAAC;KAC1B,CAAC,CAAC;IAEH,OAAO,IAAA,6CAAyB,EAAC,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Run-scoped, mutable telemetry accumulator that a plugin can write
3
+ * discovered fields into at any point during execute()/executeHttp() —
4
+ * mirrors `MetricsCollector` (src/lib/dispatch-metrics.ts) as a per-request
5
+ * instance meant to be threaded through the plugin context, but for
6
+ * run-discovered data (join keys, session info) rather than step timings.
7
+ * Funnels everything a plugin discovers mid-run into the same opaque
8
+ * `joinKeys` bag already documented in `reconciliation-record.ts`, rather
9
+ * than inventing a second bag.
10
+ */
11
+ /** Browserbase session identity/network facts recorded once per run. */
12
+ export interface SessionTelemetry {
13
+ sessionId: string;
14
+ provider: string;
15
+ ip: string | null;
16
+ ipCapturedAt: string | null;
17
+ }
18
+ /** Point-in-time view of everything accumulated on a `RunTelemetry` instance. */
19
+ export interface RunTelemetrySnapshot {
20
+ joinKeys: Record<string, unknown> | null;
21
+ session: SessionTelemetry | null;
22
+ }
23
+ /**
24
+ * Public surface `SitePluginContext.telemetry` exposes to plugins. Declared
25
+ * separately from the `RunTelemetry` class (rather than using the class
26
+ * itself as the field type) so consumers — including this repo's own test
27
+ * doubles — can satisfy the contract with a plain object; `RunTelemetry`'s
28
+ * private accumulator fields would otherwise make it structurally
29
+ * unsatisfiable by anything but the class itself.
30
+ */
31
+ export interface RunTelemetryHandle {
32
+ addJoinKeys(fields: Record<string, unknown>): void;
33
+ recordSession(info: SessionTelemetry): void;
34
+ snapshot(): RunTelemetrySnapshot;
35
+ }
36
+ /**
37
+ * Accumulates run-discovered join keys and session telemetry for a single
38
+ * dispatch invocation. Constructed per-request in `buildPluginContext`
39
+ * (`src/plugins/loader.ts`) and threaded through `SitePluginContext.telemetry`
40
+ * so a plugin can attach fields it only learns mid-run — a token minted
41
+ * mid-flow, a value read from the page after navigation — instead of being
42
+ * limited to `extractJoinKeys`'s inbound-payload-only view.
43
+ */
44
+ export declare class RunTelemetry implements RunTelemetryHandle {
45
+ private joinKeys;
46
+ private session;
47
+ /**
48
+ * Merges `fields` into the accumulated join-key bag. Later calls win on
49
+ * key collision, so a plugin can refine an early guess as the run
50
+ * progresses without losing earlier keys it doesn't repeat.
51
+ */
52
+ addJoinKeys(fields: Record<string, unknown>): void;
53
+ /**
54
+ * Records Browserbase session identity/network facts. Last-write-wins
55
+ * (whole-object replace) since a run has at most one active session at a
56
+ * time — unlike join keys, there's no reason to merge partial calls.
57
+ */
58
+ recordSession(info: SessionTelemetry): void;
59
+ /**
60
+ * Returns a defensive copy of everything accumulated so far. `joinKeys`
61
+ * stays `null` (not `{}`) when nothing was ever added, so dispatch can
62
+ * keep emitting `joinKeys: null` unchanged until a plugin actually writes
63
+ * to this collector.
64
+ */
65
+ snapshot(): RunTelemetrySnapshot;
66
+ }
67
+ //# sourceMappingURL=run-telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-telemetry.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/run-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,iFAAiF;AACjF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACnD,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC5C,QAAQ,IAAI,oBAAoB,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,qBAAa,YAAa,YAAW,kBAAkB;IACrD,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,OAAO,CAAiC;IAEhD;;;;OAIG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEjD;IAED;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAE1C;IAED;;;;;OAKG;IACH,QAAQ,IAAI,oBAAoB,CAK/B;CACF"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * Run-scoped, mutable telemetry accumulator that a plugin can write
4
+ * discovered fields into at any point during execute()/executeHttp() —
5
+ * mirrors `MetricsCollector` (src/lib/dispatch-metrics.ts) as a per-request
6
+ * instance meant to be threaded through the plugin context, but for
7
+ * run-discovered data (join keys, session info) rather than step timings.
8
+ * Funnels everything a plugin discovers mid-run into the same opaque
9
+ * `joinKeys` bag already documented in `reconciliation-record.ts`, rather
10
+ * than inventing a second bag.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.RunTelemetry = void 0;
14
+ /**
15
+ * Accumulates run-discovered join keys and session telemetry for a single
16
+ * dispatch invocation. Constructed per-request in `buildPluginContext`
17
+ * (`src/plugins/loader.ts`) and threaded through `SitePluginContext.telemetry`
18
+ * so a plugin can attach fields it only learns mid-run — a token minted
19
+ * mid-flow, a value read from the page after navigation — instead of being
20
+ * limited to `extractJoinKeys`'s inbound-payload-only view.
21
+ */
22
+ class RunTelemetry {
23
+ joinKeys = null;
24
+ session = null;
25
+ /**
26
+ * Merges `fields` into the accumulated join-key bag. Later calls win on
27
+ * key collision, so a plugin can refine an early guess as the run
28
+ * progresses without losing earlier keys it doesn't repeat.
29
+ */
30
+ addJoinKeys(fields) {
31
+ this.joinKeys = { ...this.joinKeys, ...fields };
32
+ }
33
+ /**
34
+ * Records Browserbase session identity/network facts. Last-write-wins
35
+ * (whole-object replace) since a run has at most one active session at a
36
+ * time — unlike join keys, there's no reason to merge partial calls.
37
+ */
38
+ recordSession(info) {
39
+ this.session = info;
40
+ }
41
+ /**
42
+ * Returns a defensive copy of everything accumulated so far. `joinKeys`
43
+ * stays `null` (not `{}`) when nothing was ever added, so dispatch can
44
+ * keep emitting `joinKeys: null` unchanged until a plugin actually writes
45
+ * to this collector.
46
+ */
47
+ snapshot() {
48
+ return {
49
+ joinKeys: this.joinKeys ? { ...this.joinKeys } : null,
50
+ session: this.session ? { ...this.session } : null,
51
+ };
52
+ }
53
+ }
54
+ exports.RunTelemetry = RunTelemetry;
55
+ //# sourceMappingURL=run-telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-telemetry.js","sourceRoot":"","sources":["../../../src/lib/telemetry/run-telemetry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AA8BH;;;;;;;GAOG;AACH;IACU,QAAQ,GAAmC,IAAI,CAAC;IAChD,OAAO,GAA4B,IAAI,CAAC;IAEhD;;;;OAIG;IACH,WAAW,CAAC,MAA+B;QACzC,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,IAAsB;QAClC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED;;;;;OAKG;IACH,QAAQ;QACN,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI;YACrD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI;SACnD,CAAC;IACJ,CAAC;CACF"}
@@ -24,6 +24,12 @@ export declare const submissionEnvelopeSampleSchema: z.ZodObject<{
24
24
  siteId: z.ZodString;
25
25
  requestId: z.ZodString;
26
26
  joinKeys: z.ZodDefault<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
27
+ session: z.ZodDefault<z.ZodNullable<z.ZodObject<{
28
+ id: z.ZodString;
29
+ provider: z.ZodString;
30
+ ip: z.ZodNullable<z.ZodString>;
31
+ ipCapturedAt: z.ZodNullable<z.ZodString>;
32
+ }, z.core.$strip>>>;
27
33
  inboundPayload: z.ZodUnknown;
28
34
  status: z.ZodEnum<{
29
35
  error: "error";
@@ -37,12 +43,13 @@ export declare const submissionEnvelopeSampleSchema: z.ZodObject<{
37
43
  export type SubmissionEnvelopeSample = z.infer<typeof submissionEnvelopeSampleSchema>;
38
44
  /**
39
45
  * Input to `captureSubmissionEnvelope` — `ts` and `kind` are derived
40
- * internally so callers omit them. `joinKeys` is optional so existing call
41
- * sites that don't yet resolve join keys keep compiling unchanged; an
42
- * omitted value is persisted as `null`, not left undefined.
46
+ * internally so callers omit them. `joinKeys`/`session` are optional so
47
+ * existing call sites that don't yet resolve them keep compiling unchanged;
48
+ * an omitted value is persisted as `null`, not left undefined.
43
49
  */
44
- export type SubmissionEnvelopeInput = Omit<SubmissionEnvelopeSample, "ts" | "kind" | "joinKeys"> & {
50
+ export type SubmissionEnvelopeInput = Omit<SubmissionEnvelopeSample, "ts" | "kind" | "joinKeys" | "session"> & {
45
51
  joinKeys?: Record<string, unknown> | null;
52
+ session?: SubmissionEnvelopeSample["session"];
46
53
  };
47
54
  /** Options for `captureSubmissionEnvelope`. */
48
55
  export interface CaptureSubmissionOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"submission-capture.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAShC;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;iBAAqB,CAAC;AAEjE,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAEtF;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,wBAAwB,EAAE,IAAI,GAAG,MAAM,GAAG,UAAU,CAAC,GAAG;IACjG,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5F;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,uBAAuB,EAC9B,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAef"}
1
+ {"version":3,"file":"submission-capture.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAShC;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;iBAAqB,CAAC;AAEjE,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAEtF;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,wBAAwB,EACxB,IAAI,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CACvC,GAAG;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC;CAC/C,CAAC;AAEF,+CAA+C;AAC/C,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5F;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,uBAAuB,EAC9B,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -55,6 +55,7 @@ async function captureSubmissionEnvelope(input, opts = {}) {
55
55
  ...input,
56
56
  kind: "submit",
57
57
  joinKeys: input.joinKeys ?? null,
58
+ session: input.session ?? null,
58
59
  ts: (0, date_fns_1.formatISO)(new Date()),
59
60
  };
60
61
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"submission-capture.js","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;AAEH,+CAAqD;AACrD,yCAAoC;AAEpC,uCAAqC;AAGrC,qCAAkC;AAClC,2CAA0C;AAC1C,iFAA2E;AAC3E,qDAA+D;AAE/D,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC,CAAC;AAEnE;;;;;;GAMG;AACU,QAAA,8BAA8B,GAAG,0CAAkB,CAAC;AAoBjE;;;;;;GAMG;AACI,KAAK,mCAAmC,QAAgB,EAAE,IAAY;IAC3E,MAAM,IAAA,gBAAK,EAAC,IAAA,mBAAO,EAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,IAAA,qBAAU,EAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,IAAA,8BAAoB,EAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACI,KAAK,oCACV,KAA8B,EAC9B,IAAI,GAA6B,EAAE;IAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC;IACzE,MAAM,MAAM,GAA6B;QACvC,GAAG,KAAK;QACR,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;QAChC,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,wBAAwB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,iDAAiD,QAAQ,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"submission-capture.js","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-capture.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;AAEH,+CAAqD;AACrD,yCAAoC;AAEpC,uCAAqC;AAGrC,qCAAkC;AAClC,2CAA0C;AAC1C,iFAA2E;AAC3E,qDAA+D;AAE/D,MAAM,MAAM,GAAG,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,8BAA8B,EAAE,CAAC,CAAC;AAEnE;;;;;;GAMG;AACU,QAAA,8BAA8B,GAAG,0CAAkB,CAAC;AAwBjE;;;;;;GAMG;AACI,KAAK,mCAAmC,QAAgB,EAAE,IAAY;IAC3E,MAAM,IAAA,gBAAK,EAAC,IAAA,mBAAO,EAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,IAAA,qBAAU,EAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,IAAA,8BAAoB,EAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACI,KAAK,oCACV,KAA8B,EAC9B,IAAI,GAA6B,EAAE;IAEnC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC;IACzE,MAAM,MAAM,GAA6B;QACvC,GAAG,KAAK;QACR,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;QAChC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,IAAI;QAC9B,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,wBAAwB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,iDAAiD,QAAQ,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC"}
@@ -14,13 +14,19 @@ import { type BeaconEvent, type ReconciliationRecord, type SubmitRecord } from "
14
14
  * One reconciliation row per run: the submit record's fields plus the
15
15
  * outcome of its beacon fire, distinct from submit status so "submitted but
16
16
  * the beacon did not fire" is measurable. `beaconStatus` defaults to
17
- * `"not_fired"` when no matching beacon line ever arrived.
17
+ * `"not_fired"` when no matching beacon line ever arrived. When a run has
18
+ * both a `"skipped"` line and a real `"fired"`/`"failed"` line, the real
19
+ * outcome wins the fold (see `foldReconciliationRecords`) regardless of
20
+ * which line was written first. `beaconSessionIp` is the tracking-click
21
+ * session's own outbound IP — distinct from the submit line's `session.ip`,
22
+ * since the two are separate Browserbase sessions per run.
18
23
  */
19
24
  export interface ReconciliationRow extends Omit<SubmitRecord, "kind"> {
20
25
  beaconStatus: BeaconEvent["beaconStatus"] | "not_fired";
21
26
  beaconTrackingUrl: string | null;
22
27
  beaconTs: string | null;
23
28
  beaconDurationMs: number | null;
29
+ beaconSessionIp: string | null;
24
30
  }
25
31
  /** Options for `readReconciliationRows`. */
26
32
  export interface ReadReconciliationRowsOptions {
@@ -38,8 +44,10 @@ export declare function parseReconciliationLines(ndjsonContent: string): Reconci
38
44
  * Left-joins beacon events onto submit records by `requestId`. Submit rows
39
45
  * are the base — a beacon may arrive strictly after its submit line (or
40
46
  * never), so an orphan beacon with no matching submit row is dropped rather
41
- * than synthesizing a phantom row. A later duplicate line (retry) overwrites
42
- * an earlier one for the same `requestId` and kind.
47
+ * than synthesizing a phantom row. Among beacon lines for the same
48
+ * `requestId`, the highest-`beaconRank` line wins regardless of write
49
+ * order; ties (equal rank) fall back to a later line overwriting an
50
+ * earlier one, so a duplicate/retry still resolves deterministically.
43
51
  */
44
52
  export declare function foldReconciliationRecords(records: ReconciliationRecord[]): ReconciliationRow[];
45
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"submission-reader.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAEzB,KAAK,YAAY,EAClB,MAAM,uCAAuC,CAAC;AAI/C;;;;;GAKG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC;IACnE,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,GAAG,WAAW,CAAC;IACxD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,4CAA4C;AAC5C,MAAM,WAAW,6BAA6B;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,oBAAoB,EAAE,CA2BtF;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,iBAAiB,EAAE,CA6B9F;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,GAAE,6BAAkC,GACvC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAM9B"}
1
+ {"version":3,"file":"submission-reader.d.ts","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAEzB,KAAK,YAAY,EAClB,MAAM,uCAAuC,CAAC;AAI/C;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC;IACnE,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,GAAG,WAAW,CAAC;IACxD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,4CAA4C;AAC5C,MAAM,WAAW,6BAA6B;IAC5C,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,oBAAoB,EAAE,CA2BtF;AAcD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,iBAAiB,EAAE,CA2C9F;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,GAAE,6BAAkC,GACvC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAM9B"}
@@ -58,12 +58,25 @@ function parseReconciliationLines(ndjsonContent) {
58
58
  }
59
59
  return records;
60
60
  }
61
+ /**
62
+ * Rank of a beacon outcome for fold precedence: a real `fired`/`failed`
63
+ * outcome always outranks `skipped`, because `dispatch()` writes `skipped`
64
+ * synchronously for any self-managing plugin (`loader.ts`) before that
65
+ * plugin's own later-recorded real outcome can arrive — write order alone
66
+ * is not a safe proxy for which line reflects reality. Equal-rank lines
67
+ * (e.g. a retried `fired`) fall through to array order, i.e. last one wins.
68
+ */
69
+ function beaconRank(beaconStatus) {
70
+ return beaconStatus === "skipped" ? 0 : 1;
71
+ }
61
72
  /**
62
73
  * Left-joins beacon events onto submit records by `requestId`. Submit rows
63
74
  * are the base — a beacon may arrive strictly after its submit line (or
64
75
  * never), so an orphan beacon with no matching submit row is dropped rather
65
- * than synthesizing a phantom row. A later duplicate line (retry) overwrites
66
- * an earlier one for the same `requestId` and kind.
76
+ * than synthesizing a phantom row. Among beacon lines for the same
77
+ * `requestId`, the highest-`beaconRank` line wins regardless of write
78
+ * order; ties (equal rank) fall back to a later line overwriting an
79
+ * earlier one, so a duplicate/retry still resolves deterministically.
67
80
  */
68
81
  function foldReconciliationRecords(records) {
69
82
  const rows = new Map();
@@ -77,20 +90,31 @@ function foldReconciliationRecords(records) {
77
90
  beaconTrackingUrl: null,
78
91
  beaconTs: null,
79
92
  beaconDurationMs: null,
93
+ beaconSessionIp: null,
80
94
  });
81
95
  }
96
+ const winningBeacons = new Map();
82
97
  for (const record of records) {
83
98
  if (record.kind !== "beacon")
84
99
  continue;
85
- const row = rows.get(record.requestId);
100
+ const current = winningBeacons.get(record.requestId);
101
+ if (current !== undefined &&
102
+ beaconRank(current.beaconStatus) > beaconRank(record.beaconStatus)) {
103
+ continue;
104
+ }
105
+ winningBeacons.set(record.requestId, record);
106
+ }
107
+ for (const [requestId, beacon] of winningBeacons) {
108
+ const row = rows.get(requestId);
86
109
  if (row === undefined)
87
110
  continue;
88
- rows.set(record.requestId, {
111
+ rows.set(requestId, {
89
112
  ...row,
90
- beaconStatus: record.beaconStatus,
91
- beaconTrackingUrl: record.trackingUrl,
92
- beaconTs: record.ts,
93
- beaconDurationMs: record.durationMs,
113
+ beaconStatus: beacon.beaconStatus,
114
+ beaconTrackingUrl: beacon.trackingUrl,
115
+ beaconTs: beacon.ts,
116
+ beaconDurationMs: beacon.durationMs,
117
+ beaconSessionIp: beacon.sessionIp,
94
118
  });
95
119
  }
96
120
  return Array.from(rows.values());
@@ -1 +1 @@
1
- {"version":3,"file":"submission-reader.js","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-reader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"submission-reader.js","sourceRoot":"","sources":["../../../src/lib/telemetry/submission-reader.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracking-click.d.ts","sourceRoot":"","sources":["../../src/lib/tracking-click.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAqBH;;;;GAIG;AACH,MAAM,WAAW,kCAAkC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAiFD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,kCAAkC,GAClD,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3E"}
1
+ {"version":3,"file":"tracking-click.d.ts","sourceRoot":"","sources":["../../src/lib/tracking-click.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAqBH;;;;GAIG;AACH,MAAM,WAAW,kCAAkC;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAqGD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,kCAAkC,GAClD,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAO3E"}
@@ -38,6 +38,23 @@ async function captureBeaconOutcomeSafely(input) {
38
38
  logger.warn(`beacon outcome capture failed: ${(0, errors_1.toErrorMessage)(err)}`);
39
39
  }
40
40
  }
41
+ /**
42
+ * Resolves the given session's outbound IP for the beacon record. Never
43
+ * throws — a resolution failure (or a session/provider without the
44
+ * accessor) yields `null` rather than blocking the beacon write, matching
45
+ * the same never-throw contract `getOutboundIp` itself already applies.
46
+ */
47
+ async function resolveSessionIp(session) {
48
+ if (!session?.getOutboundIp)
49
+ return null;
50
+ try {
51
+ return await session.getOutboundIp();
52
+ }
53
+ catch (err) {
54
+ logger.warn(`tracking click session IP resolution failed: ${(0, errors_1.toErrorMessage)(err)}`);
55
+ return null;
56
+ }
57
+ }
41
58
  /**
42
59
  * Navigates a Browserbase session to the tracking URL. Errors are logged
43
60
  * and swallowed — the apply already succeeded, so a failed tracking click
@@ -65,6 +82,7 @@ async function executeTrackingClick(trackingUrl, siteId, reconciliation) {
65
82
  beaconStatus: "fired",
66
83
  trackingUrl,
67
84
  durationMs: Date.now() - startedAt,
85
+ sessionIp: await resolveSessionIp(session),
68
86
  });
69
87
  }
70
88
  }
@@ -79,6 +97,7 @@ async function executeTrackingClick(trackingUrl, siteId, reconciliation) {
79
97
  beaconStatus: "failed",
80
98
  trackingUrl,
81
99
  durationMs: Date.now() - startedAt,
100
+ sessionIp: await resolveSessionIp(session),
82
101
  });
83
102
  }
84
103
  }