@genn-inc/cluebase-frontend-sdk 0.0.6 → 0.0.9
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/dist/_generated/correlation-attribute-keys.d.ts +3 -0
- package/dist/_generated/correlation-attribute-keys.js +35 -0
- package/dist/_generated/diagnostic-codes.d.ts +4 -0
- package/dist/_generated/diagnostic-codes.js +48 -0
- package/dist/_generated/drop-reasons.d.ts +2 -0
- package/dist/_generated/drop-reasons.js +25 -0
- package/dist/_generated/ingest-routes.d.ts +5 -0
- package/dist/_generated/ingest-routes.js +12 -0
- package/dist/context/trace.js +2 -4
- package/dist/exporter/batch.d.ts +23 -26
- package/dist/exporter/batch.js +254 -289
- package/dist/exporter/browser-outbox-records.d.ts +7 -24
- package/dist/exporter/browser-outbox-records.js +6 -94
- package/dist/exporter/browser-outbox.d.ts +23 -28
- package/dist/exporter/browser-outbox.js +99 -211
- package/dist/exporter/client.d.ts +24 -34
- package/dist/exporter/client.js +107 -318
- package/dist/exporter/delivery-pipeline.d.ts +72 -0
- package/dist/exporter/delivery-pipeline.js +199 -0
- package/dist/exporter/delivery-response-contract.d.ts +5 -81
- package/dist/exporter/delivery-response-contract.js +4 -166
- package/dist/exporter/delivery-response.d.ts +8 -4
- package/dist/exporter/delivery-response.js +62 -133
- package/dist/exporter/diagnostics.d.ts +2 -1
- package/dist/exporter/diagnostics.js +1 -25
- package/dist/exporter/event-id.d.ts +1 -0
- package/dist/exporter/event-id.js +3 -0
- package/dist/exporter/observation-source-event-exporter.d.ts +1 -1
- package/dist/exporter/observation-source-event-exporter.js +2 -2
- package/dist/exporter/parameter-encryption.d.ts +10 -0
- package/dist/exporter/parameter-encryption.js +219 -0
- package/dist/exporter/parameter-snapshot.js +25 -3
- package/dist/exporter/sdk-core-delivery.d.ts +226 -0
- package/dist/exporter/sdk-core-delivery.js +97 -0
- package/dist/exporter/sdk-core-wasm.d.ts +24 -1
- package/dist/exporter/sdk-core-wasm.js +31 -3
- package/dist/exporter/source-event.d.ts +2 -0
- package/dist/exporter/source-event.js +17 -0
- package/dist/exporter/span-to-source-signal.d.ts +1 -1
- package/dist/exporter/span-to-source-signal.js +20 -140
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -3
- package/dist/instrumentation/network.d.ts +1 -1
- package/dist/instrumentation/network.js +17 -0
- package/dist/provider/_version.d.ts +1 -1
- package/dist/provider/_version.js +1 -1
- package/dist/provider/config.js +16 -3
- package/dist/provider/constants.js +0 -1
- package/dist/provider/contracts.d.ts +2 -0
- package/dist/provider/contracts.js +2 -0
- package/dist/provider/lifecycle-event-dedup.d.ts +7 -0
- package/dist/provider/lifecycle-event-dedup.js +31 -0
- package/dist/provider/sdk-encryption-store.d.ts +7 -0
- package/dist/provider/sdk-encryption-store.js +15 -0
- package/dist/provider/sdk-event-pipeline.d.ts +1 -3
- package/dist/provider/sdk-event-pipeline.js +0 -15
- package/dist/provider/sdk-otel-pipeline.d.ts +2 -1
- package/dist/provider/sdk-otel-pipeline.js +2 -11
- package/dist/provider/sdk-runtime-surfaces.d.ts +3 -2
- package/dist/provider/sdk-runtime-surfaces.js +7 -6
- package/dist/provider/sdk.js +88 -54
- package/dist/provider/types.d.ts +14 -19
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.d.ts +18 -9
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.js +170 -29
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm +0 -0
- package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm.d.ts +10 -9
- package/package.json +1 -1
- package/dist/provider/usage-governor.d.ts +0 -7
- package/dist/provider/usage-governor.js +0 -114
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { applyTransportResult, attemptRequest, beginClose, capturePermit, closeDriver, adoptRestoredBatch as coreAdoptRestoredBatch, setConsent as coreSetConsent, enqueueEvent, fenceQueue, openConsent, openDriver, pendingEventCount, planNextStep, queueDepth, setBrowserToken, } from "./sdk-core-delivery.js";
|
|
2
|
+
const RELEASED_PERMIT = Object.freeze({
|
|
3
|
+
generation: "",
|
|
4
|
+
gate_id: "",
|
|
5
|
+
permitted_at_start: false,
|
|
6
|
+
capture_open_at_start: false,
|
|
7
|
+
});
|
|
8
|
+
const RELEASED_ENQUEUE_REPORT = Object.freeze({
|
|
9
|
+
retained: false,
|
|
10
|
+
overflowed_event_keys: [],
|
|
11
|
+
diagnostics: [],
|
|
12
|
+
});
|
|
13
|
+
const RELEASED_RESTORE_REPORT = Object.freeze({
|
|
14
|
+
adopted: false,
|
|
15
|
+
event_keys: [],
|
|
16
|
+
});
|
|
17
|
+
const RELEASED_QUEUE_DEPTH = Object.freeze({
|
|
18
|
+
draft_count: 0,
|
|
19
|
+
draft_body_bytes: 0,
|
|
20
|
+
pending_bytes: 0,
|
|
21
|
+
});
|
|
22
|
+
const RELEASED_FENCE_REPORT = Object.freeze({
|
|
23
|
+
target_ordinal: 0,
|
|
24
|
+
oversized_event_keys: [],
|
|
25
|
+
frame_admits_no_event: true,
|
|
26
|
+
diagnostics: [],
|
|
27
|
+
});
|
|
28
|
+
const RELEASED_RUN_SUMMARY = Object.freeze({
|
|
29
|
+
observations: [],
|
|
30
|
+
attempts: 0,
|
|
31
|
+
stop: "queue_drained",
|
|
32
|
+
});
|
|
33
|
+
export class DeliveryPipeline {
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.released = false;
|
|
36
|
+
this.consentHandle = openConsent(options.initialConsent);
|
|
37
|
+
this.driverOptions = {
|
|
38
|
+
transport: {
|
|
39
|
+
surface: "frontend",
|
|
40
|
+
endpoint: options.endpoint,
|
|
41
|
+
project_key: options.projectKey,
|
|
42
|
+
sdk_request: options.sdkRequest,
|
|
43
|
+
sdk_version: options.sdkVersion,
|
|
44
|
+
source_schema_version: options.sourceSchemaVersion,
|
|
45
|
+
},
|
|
46
|
+
queue_limits: options.queueLimits,
|
|
47
|
+
...(options.requestTimeoutMs === undefined
|
|
48
|
+
? {}
|
|
49
|
+
: { request_timeout_ms: options.requestTimeoutMs }),
|
|
50
|
+
};
|
|
51
|
+
this.handle = openDriver(this.driverOptions, this.consentHandle);
|
|
52
|
+
this.transport = options.transport;
|
|
53
|
+
this.clock = options.clock;
|
|
54
|
+
}
|
|
55
|
+
reset() {
|
|
56
|
+
if (this.released)
|
|
57
|
+
return;
|
|
58
|
+
closeDriver(this.handle);
|
|
59
|
+
this.handle = openDriver(this.driverOptions, this.consentHandle);
|
|
60
|
+
}
|
|
61
|
+
permit() {
|
|
62
|
+
return this.released ? RELEASED_PERMIT : capturePermit(this.handle);
|
|
63
|
+
}
|
|
64
|
+
admit(event, permit) {
|
|
65
|
+
if (this.released)
|
|
66
|
+
return RELEASED_ENQUEUE_REPORT;
|
|
67
|
+
return enqueueEvent(this.handle, {
|
|
68
|
+
event_key: event.eventKey,
|
|
69
|
+
byte_length: event.byteLength,
|
|
70
|
+
permit,
|
|
71
|
+
...(event.diagnosticCanonicalBytes === undefined
|
|
72
|
+
? {}
|
|
73
|
+
: { diagnostic_canonical_bytes: event.diagnosticCanonicalBytes }),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
adoptRestoredBatch(ordinal, events) {
|
|
77
|
+
if (this.released)
|
|
78
|
+
return RELEASED_RESTORE_REPORT;
|
|
79
|
+
return coreAdoptRestoredBatch(this.handle, ordinal, events);
|
|
80
|
+
}
|
|
81
|
+
depth(envelopeOverheadBytes) {
|
|
82
|
+
if (this.released)
|
|
83
|
+
return RELEASED_QUEUE_DEPTH;
|
|
84
|
+
return queueDepth(this.handle, envelopeOverheadBytes);
|
|
85
|
+
}
|
|
86
|
+
pendingCount() {
|
|
87
|
+
return this.released ? 0 : pendingEventCount(this.handle);
|
|
88
|
+
}
|
|
89
|
+
fence(envelopeOverheadBytes) {
|
|
90
|
+
if (this.released)
|
|
91
|
+
return RELEASED_FENCE_REPORT;
|
|
92
|
+
return fenceQueue(this.handle, envelopeOverheadBytes);
|
|
93
|
+
}
|
|
94
|
+
rememberBrowserToken(token) {
|
|
95
|
+
if (this.released)
|
|
96
|
+
return;
|
|
97
|
+
setBrowserToken(this.handle, token);
|
|
98
|
+
}
|
|
99
|
+
declareConsent(consent) {
|
|
100
|
+
return coreSetConsent(this.consentHandle, consent);
|
|
101
|
+
}
|
|
102
|
+
beginClose() {
|
|
103
|
+
if (this.released)
|
|
104
|
+
return;
|
|
105
|
+
beginClose(this.handle);
|
|
106
|
+
}
|
|
107
|
+
dispose() {
|
|
108
|
+
if (this.released)
|
|
109
|
+
return false;
|
|
110
|
+
this.released = true;
|
|
111
|
+
return closeDriver(this.handle);
|
|
112
|
+
}
|
|
113
|
+
async run(input) {
|
|
114
|
+
if (this.released)
|
|
115
|
+
return RELEASED_RUN_SUMMARY;
|
|
116
|
+
const observations = [];
|
|
117
|
+
let attempts = 0;
|
|
118
|
+
let stop = "queue_drained";
|
|
119
|
+
const deadlineMs = () => typeof input.deadlineMs === "function"
|
|
120
|
+
? input.deadlineMs()
|
|
121
|
+
: input.deadlineMs;
|
|
122
|
+
while (true) {
|
|
123
|
+
if (this.released)
|
|
124
|
+
break;
|
|
125
|
+
const step = planNextStep(this.handle, this.clock.nowMs(), deadlineMs());
|
|
126
|
+
if (step.kind === "idle")
|
|
127
|
+
break;
|
|
128
|
+
if (step.kind === "blocked") {
|
|
129
|
+
stop = step.reason;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
if (step.kind === "wait_retry") {
|
|
133
|
+
await this.clock.sleep(step.delay_ms);
|
|
134
|
+
if (this.clock.nowMs() < step.resume_at_ms) {
|
|
135
|
+
stop = "retry_not_due";
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const batch = input.body(step.batch_id, step.event_keys);
|
|
141
|
+
if (!batch) {
|
|
142
|
+
stop = "batch_unavailable";
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
attempts += 1;
|
|
146
|
+
const request = attemptRequest(this.handle, {
|
|
147
|
+
attemptId: step.attempt_id,
|
|
148
|
+
body: batch.body,
|
|
149
|
+
timeoutMs: step.timeout_ms,
|
|
150
|
+
...(batch.diagnosticCanonicalBytes === undefined
|
|
151
|
+
? {}
|
|
152
|
+
: { batchCanonicalBytes: batch.diagnosticCanonicalBytes }),
|
|
153
|
+
});
|
|
154
|
+
const outcome = await this.transport(request);
|
|
155
|
+
if (this.released)
|
|
156
|
+
break;
|
|
157
|
+
const report = applyTransportResult(this.handle, step.attempt_id, outcome, this.clock.nowMs());
|
|
158
|
+
const observation = observe(report);
|
|
159
|
+
observations.push(observation);
|
|
160
|
+
input.onObservation?.(observation);
|
|
161
|
+
if (report.progress.kind === "retries_exhausted") {
|
|
162
|
+
stop = "retries_exhausted";
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
if (report.progress.kind === "consent_revoked") {
|
|
166
|
+
stop = "consent_revoked";
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { observations, attempts, stop };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const observe = (report) => {
|
|
174
|
+
const progress = report.progress;
|
|
175
|
+
const settled = progress.kind === "settled" ? progress.settled_event_keys : [];
|
|
176
|
+
const dropped = progress.kind === "settled"
|
|
177
|
+
? progress.dropped_event_keys
|
|
178
|
+
: progress.kind === "dropped_oversized"
|
|
179
|
+
? [progress.event_key]
|
|
180
|
+
: [];
|
|
181
|
+
const droppedEventCount = Math.max(dropped.length, report.decision?.result.dropped_event_count ?? 0);
|
|
182
|
+
return {
|
|
183
|
+
progress,
|
|
184
|
+
diagnostics: report.diagnostics,
|
|
185
|
+
settledEventKeys: settled,
|
|
186
|
+
droppedEventKeys: dropped,
|
|
187
|
+
droppedEventCount,
|
|
188
|
+
httpStatus: report.decision?.http_status ?? null,
|
|
189
|
+
reason: report.decision?.result.reason ?? null,
|
|
190
|
+
...(report.decision?.privacy_policy === undefined
|
|
191
|
+
? {}
|
|
192
|
+
: { privacyPolicy: report.decision.privacy_policy }),
|
|
193
|
+
...(report.decision?.sdk_encryption === undefined
|
|
194
|
+
? {}
|
|
195
|
+
: { sdkEncryption: report.decision.sdk_encryption }),
|
|
196
|
+
directiveUnreadable: report.decision?.directive_unreadable === true,
|
|
197
|
+
diagnosticCodes: report.decision?.diagnostic_codes ?? [],
|
|
198
|
+
};
|
|
199
|
+
};
|
|
@@ -6,6 +6,7 @@ declare const ingestRetryStrategySchema: z.ZodEnum<{
|
|
|
6
6
|
mark_failed: "mark_failed";
|
|
7
7
|
drop_event: "drop_event";
|
|
8
8
|
}>;
|
|
9
|
+
export type IngestRetryStrategy = z.infer<typeof ingestRetryStrategySchema>;
|
|
9
10
|
export declare const ingestPrivacyPolicySchema: z.ZodObject<{
|
|
10
11
|
token: z.ZodString;
|
|
11
12
|
entries: z.ZodArray<z.ZodObject<{
|
|
@@ -19,85 +20,8 @@ export declare const ingestPrivacyPolicySchema: z.ZodObject<{
|
|
|
19
20
|
}, z.core.$strict>>;
|
|
20
21
|
}, z.core.$strict>;
|
|
21
22
|
export type IngestPrivacyPolicy = z.output<typeof ingestPrivacyPolicySchema>;
|
|
22
|
-
export declare const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
submitted_event_count: z.ZodNumber;
|
|
27
|
-
accepted_event_count: z.ZodNumber;
|
|
28
|
-
dropped_event_count: z.ZodNumber;
|
|
29
|
-
dropped_events: z.ZodArray<z.ZodObject<{
|
|
30
|
-
event_index: z.ZodNumber;
|
|
31
|
-
reason: z.ZodString;
|
|
32
|
-
source_event_payload_fingerprint: z.ZodNullable<z.ZodString>;
|
|
33
|
-
}, z.core.$strict>>;
|
|
34
|
-
duplicate: z.ZodBoolean;
|
|
35
|
-
governor: z.ZodOptional<z.ZodObject<{
|
|
36
|
-
disabledCapabilities: z.ZodArray<z.ZodEnum<{
|
|
37
|
-
event_collection: "event_collection";
|
|
38
|
-
replay_storage: "replay_storage";
|
|
39
|
-
ai_generation: "ai_generation";
|
|
40
|
-
raw_observation_storage: "raw_observation_storage";
|
|
41
|
-
retention_growth: "retention_growth";
|
|
42
|
-
}>>;
|
|
43
|
-
limitReasons: z.ZodArray<z.ZodObject<{
|
|
44
|
-
limitKind: z.ZodEnum<{
|
|
45
|
-
monthly_overage_amount_limit: "monthly_overage_amount_limit";
|
|
46
|
-
internal_cost_limit: "internal_cost_limit";
|
|
47
|
-
internal_limit: "internal_limit";
|
|
48
|
-
operator_global_monthly_cost_limit: "operator_global_monthly_cost_limit";
|
|
49
|
-
}>;
|
|
50
|
-
meterKey: z.ZodString;
|
|
51
|
-
thresholdStage: z.ZodEnum<{
|
|
52
|
-
info: "info";
|
|
53
|
-
warning: "warning";
|
|
54
|
-
urgent: "urgent";
|
|
55
|
-
reached: "reached";
|
|
56
|
-
}>;
|
|
57
|
-
currentValue: z.ZodNumber;
|
|
58
|
-
limitValue: z.ZodNumber;
|
|
59
|
-
retryAfterAt: z.ZodNullable<z.ZodString>;
|
|
60
|
-
}, z.core.$strip>>;
|
|
61
|
-
retryAfterAt: z.ZodNullable<z.ZodString>;
|
|
62
|
-
}, z.core.$strip>>;
|
|
63
|
-
privacy_policy: z.ZodOptional<z.ZodObject<{
|
|
64
|
-
token: z.ZodString;
|
|
65
|
-
entries: z.ZodArray<z.ZodObject<{
|
|
66
|
-
method: z.ZodString;
|
|
67
|
-
path_template: z.ZodString;
|
|
68
|
-
direction: z.ZodEnum<{
|
|
69
|
-
request: "request";
|
|
70
|
-
response: "response";
|
|
71
|
-
}>;
|
|
72
|
-
field_path: z.ZodString;
|
|
73
|
-
}, z.core.$strict>>;
|
|
74
|
-
}, z.core.$strict>>;
|
|
75
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
76
|
-
accepted: z.ZodLiteral<false>;
|
|
77
|
-
status: z.ZodEnum<{
|
|
78
|
-
rejected: "rejected";
|
|
79
|
-
failed: "failed";
|
|
80
|
-
}>;
|
|
81
|
-
reason: z.ZodString;
|
|
82
|
-
retry_strategy: z.ZodEnum<{
|
|
83
|
-
split_batch: "split_batch";
|
|
84
|
-
retry_same_batch: "retry_same_batch";
|
|
85
|
-
stop_and_report: "stop_and_report";
|
|
86
|
-
mark_failed: "mark_failed";
|
|
87
|
-
drop_event: "drop_event";
|
|
88
|
-
}>;
|
|
89
|
-
submitted_event_count: z.ZodOptional<z.ZodNumber>;
|
|
90
|
-
accepted_event_count: z.ZodOptional<z.ZodNumber>;
|
|
91
|
-
dropped_event_count: z.ZodOptional<z.ZodNumber>;
|
|
92
|
-
dropped_events: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
93
|
-
event_index: z.ZodNumber;
|
|
94
|
-
reason: z.ZodString;
|
|
95
|
-
source_event_payload_fingerprint: z.ZodNullable<z.ZodString>;
|
|
96
|
-
}, z.core.$strict>>>;
|
|
97
|
-
limits: z.ZodOptional<z.ZodObject<{
|
|
98
|
-
hard_max_payload_bytes: z.ZodNumber;
|
|
99
|
-
max_event_bytes: z.ZodNumber;
|
|
100
|
-
}, z.core.$strip>>;
|
|
101
|
-
}, z.core.$strip>], "accepted">;
|
|
102
|
-
export type IngestRetryStrategy = z.infer<typeof ingestRetryStrategySchema>;
|
|
23
|
+
export declare const ingestSdkEncryptionSchema: z.ZodObject<{
|
|
24
|
+
key_version: z.ZodNumber;
|
|
25
|
+
public_key: z.ZodString;
|
|
26
|
+
}, z.core.$strict>;
|
|
103
27
|
export {};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { COST_CAPABILITIES, LIMIT_KINDS, } from "../_generated/usage-governor-tables.js";
|
|
3
|
-
const MAX_INGEST_EVENTS_PER_BATCH = 10000;
|
|
4
2
|
const ingestRetryStrategySchema = z.enum([
|
|
5
3
|
"split_batch",
|
|
6
4
|
"retry_same_batch",
|
|
@@ -8,34 +6,6 @@ const ingestRetryStrategySchema = z.enum([
|
|
|
8
6
|
"mark_failed",
|
|
9
7
|
"drop_event",
|
|
10
8
|
]);
|
|
11
|
-
const ingestDroppedEventSchema = z
|
|
12
|
-
.object({
|
|
13
|
-
event_index: z.number().int().nonnegative(),
|
|
14
|
-
reason: z.string().trim().min(1).max(128),
|
|
15
|
-
source_event_payload_fingerprint: z
|
|
16
|
-
.string()
|
|
17
|
-
.regex(/^[0-9a-f]{64}$/)
|
|
18
|
-
.nullable(),
|
|
19
|
-
})
|
|
20
|
-
.strict();
|
|
21
|
-
const ingestUsageGovernorFeedbackSchema = z.object({
|
|
22
|
-
disabledCapabilities: z.array(z.enum(COST_CAPABILITIES)),
|
|
23
|
-
limitReasons: z.array(z.object({
|
|
24
|
-
limitKind: z.enum(LIMIT_KINDS),
|
|
25
|
-
meterKey: z.string().trim().min(1),
|
|
26
|
-
thresholdStage: z.enum(["info", "warning", "urgent", "reached"]),
|
|
27
|
-
currentValue: z.number().nonnegative(),
|
|
28
|
-
limitValue: z.number().nonnegative(),
|
|
29
|
-
retryAfterAt: z.string().datetime({ offset: true }).nullable(),
|
|
30
|
-
})),
|
|
31
|
-
retryAfterAt: z.string().datetime({ offset: true }).nullable(),
|
|
32
|
-
});
|
|
33
|
-
const boundedCount = z
|
|
34
|
-
.number()
|
|
35
|
-
.int()
|
|
36
|
-
.nonnegative()
|
|
37
|
-
.max(MAX_INGEST_EVENTS_PER_BATCH);
|
|
38
|
-
const positiveCount = boundedCount.refine((count) => count > 0);
|
|
39
9
|
export const ingestPrivacyPolicySchema = z
|
|
40
10
|
.object({
|
|
41
11
|
token: z.string().trim().min(1).max(200),
|
|
@@ -51,141 +21,9 @@ export const ingestPrivacyPolicySchema = z
|
|
|
51
21
|
.max(500),
|
|
52
22
|
})
|
|
53
23
|
.strict();
|
|
54
|
-
const
|
|
24
|
+
export const ingestSdkEncryptionSchema = z
|
|
55
25
|
.object({
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
status: z.literal("received"),
|
|
59
|
-
submitted_event_count: positiveCount,
|
|
60
|
-
accepted_event_count: positiveCount,
|
|
61
|
-
dropped_event_count: boundedCount,
|
|
62
|
-
dropped_events: z
|
|
63
|
-
.array(ingestDroppedEventSchema)
|
|
64
|
-
.max(MAX_INGEST_EVENTS_PER_BATCH),
|
|
65
|
-
duplicate: z.boolean(),
|
|
66
|
-
governor: ingestUsageGovernorFeedbackSchema.optional(),
|
|
67
|
-
privacy_policy: ingestPrivacyPolicySchema.optional(),
|
|
26
|
+
key_version: z.number().int().positive(),
|
|
27
|
+
public_key: z.string().trim().min(1).max(2048),
|
|
68
28
|
})
|
|
69
|
-
.
|
|
70
|
-
if (value.submitted_event_count !==
|
|
71
|
-
value.accepted_event_count + value.dropped_event_count) {
|
|
72
|
-
ctx.addIssue({
|
|
73
|
-
code: z.ZodIssueCode.custom,
|
|
74
|
-
path: ["submitted_event_count"],
|
|
75
|
-
message: "submitted count must equal accepted plus dropped counts",
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
if (!value.duplicate || value.dropped_events.length > 0) {
|
|
79
|
-
validateDroppedEventDetails(value.submitted_event_count, value.dropped_event_count, value.dropped_events, ctx);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
const observationSourceEventBatchRejectedResponseSchema = z
|
|
83
|
-
.object({
|
|
84
|
-
accepted: z.literal(false),
|
|
85
|
-
status: z.enum(["rejected", "failed"]),
|
|
86
|
-
reason: z.string().trim().min(1),
|
|
87
|
-
retry_strategy: ingestRetryStrategySchema,
|
|
88
|
-
submitted_event_count: positiveCount.optional(),
|
|
89
|
-
accepted_event_count: boundedCount.optional(),
|
|
90
|
-
dropped_event_count: boundedCount.optional(),
|
|
91
|
-
dropped_events: z
|
|
92
|
-
.array(ingestDroppedEventSchema)
|
|
93
|
-
.max(MAX_INGEST_EVENTS_PER_BATCH)
|
|
94
|
-
.optional(),
|
|
95
|
-
limits: z
|
|
96
|
-
.object({
|
|
97
|
-
hard_max_payload_bytes: z.number().int().positive(),
|
|
98
|
-
max_event_bytes: z.number().int().positive(),
|
|
99
|
-
})
|
|
100
|
-
.refine((limits) => limits.max_event_bytes <= limits.hard_max_payload_bytes)
|
|
101
|
-
.optional(),
|
|
102
|
-
})
|
|
103
|
-
.superRefine((value, ctx) => {
|
|
104
|
-
const counts = [
|
|
105
|
-
value.submitted_event_count,
|
|
106
|
-
value.accepted_event_count,
|
|
107
|
-
value.dropped_event_count,
|
|
108
|
-
];
|
|
109
|
-
const hasAnyCount = counts.some((count) => count !== undefined);
|
|
110
|
-
const hasAllCounts = counts.every((count) => count !== undefined);
|
|
111
|
-
if (hasAnyCount !== hasAllCounts) {
|
|
112
|
-
ctx.addIssue({
|
|
113
|
-
code: z.ZodIssueCode.custom,
|
|
114
|
-
path: ["submitted_event_count"],
|
|
115
|
-
message: "rejected response counts must be all present or all absent",
|
|
116
|
-
});
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (hasAllCounts) {
|
|
120
|
-
const [submitted, accepted, dropped] = counts;
|
|
121
|
-
if (accepted > submitted ||
|
|
122
|
-
dropped > submitted ||
|
|
123
|
-
accepted + dropped > submitted) {
|
|
124
|
-
ctx.addIssue({
|
|
125
|
-
code: z.ZodIssueCode.custom,
|
|
126
|
-
path: ["dropped_event_count"],
|
|
127
|
-
message: "rejected counts must not exceed submitted count",
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (value.retry_strategy === "drop_event") {
|
|
132
|
-
if (!hasAllCounts) {
|
|
133
|
-
ctx.addIssue({
|
|
134
|
-
code: z.ZodIssueCode.custom,
|
|
135
|
-
path: ["submitted_event_count"],
|
|
136
|
-
message: "drop rejection requires all counts",
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
const [submitted, accepted, dropped] = counts;
|
|
141
|
-
if (accepted !== 0 || dropped !== submitted) {
|
|
142
|
-
ctx.addIssue({
|
|
143
|
-
code: z.ZodIssueCode.custom,
|
|
144
|
-
path: ["dropped_event_count"],
|
|
145
|
-
message: "drop rejection must reject every submitted event",
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
validateDroppedEventDetails(submitted, dropped, value.dropped_events ?? [], ctx);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
else if ((value.dropped_events?.length ?? 0) > 0) {
|
|
152
|
-
ctx.addIssue({
|
|
153
|
-
code: z.ZodIssueCode.custom,
|
|
154
|
-
path: ["dropped_events"],
|
|
155
|
-
message: "non-drop rejection must not contain dropped event details",
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
if ((value.retry_strategy === "split_batch") !==
|
|
159
|
-
(value.limits !== undefined)) {
|
|
160
|
-
ctx.addIssue({
|
|
161
|
-
code: z.ZodIssueCode.custom,
|
|
162
|
-
path: ["limits"],
|
|
163
|
-
message: "byte limits are valid only for split rejection",
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
export const observationSourceEventBatchResponseSchema = z.discriminatedUnion("accepted", [
|
|
168
|
-
observationSourceEventBatchAcceptedResponseSchema,
|
|
169
|
-
observationSourceEventBatchRejectedResponseSchema,
|
|
170
|
-
]);
|
|
171
|
-
function validateDroppedEventDetails(submittedCount, droppedCount, droppedEvents, ctx) {
|
|
172
|
-
if (droppedEvents.length !== droppedCount) {
|
|
173
|
-
ctx.addIssue({
|
|
174
|
-
code: z.ZodIssueCode.custom,
|
|
175
|
-
path: ["dropped_events"],
|
|
176
|
-
message: "dropped event details must match dropped count",
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
const indexes = new Set();
|
|
180
|
-
for (const [detailIndex, detail] of droppedEvents.entries()) {
|
|
181
|
-
if (detail.event_index >= submittedCount ||
|
|
182
|
-
indexes.has(detail.event_index)) {
|
|
183
|
-
ctx.addIssue({
|
|
184
|
-
code: z.ZodIssueCode.custom,
|
|
185
|
-
path: ["dropped_events", detailIndex, "event_index"],
|
|
186
|
-
message: "dropped event indexes must be valid and unique",
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
indexes.add(detail.event_index);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
29
|
+
.strict();
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type IngestRetryStrategy } from "./delivery-response-contract.js";
|
|
1
|
+
import type { IngestRetryStrategy } from "./delivery-response-contract.js";
|
|
3
2
|
import type { DiagnosticCode } from "./diagnostics.js";
|
|
4
|
-
|
|
3
|
+
import { type TransportOutcome } from "./sdk-core-delivery.js";
|
|
5
4
|
export type { IngestRetryStrategy } from "./delivery-response-contract.js";
|
|
6
5
|
export type BrowserDeliveryDecision = {
|
|
7
6
|
readonly ok: boolean;
|
|
8
7
|
readonly privacyPolicy?: unknown;
|
|
8
|
+
readonly sdkEncryption?: unknown;
|
|
9
|
+
readonly directiveUnreadable: boolean;
|
|
9
10
|
readonly retryStrategy: IngestRetryStrategy | null;
|
|
10
|
-
readonly governor: IngestUsageGovernorFeedback | null;
|
|
11
11
|
readonly observationIngestBatchId?: string;
|
|
12
12
|
readonly droppedEventCount: number;
|
|
13
13
|
readonly acceptedEventCount: number;
|
|
14
14
|
readonly acceptedPartial: boolean;
|
|
15
|
+
readonly acceptedFiltered: boolean;
|
|
15
16
|
readonly reason: string | null;
|
|
16
17
|
readonly diagnosticCodes: readonly DiagnosticCode[];
|
|
17
18
|
};
|
|
@@ -20,4 +21,7 @@ export declare const evaluateBrowserDeliveryResponse: (input: {
|
|
|
20
21
|
readonly bodyText: string;
|
|
21
22
|
readonly localSubmittedCount: number;
|
|
22
23
|
}) => BrowserDeliveryDecision;
|
|
24
|
+
export declare const evaluateBrowserTransportOutcome: (outcome: Exclude<TransportOutcome, {
|
|
25
|
+
kind: "response";
|
|
26
|
+
}>) => BrowserDeliveryDecision;
|
|
23
27
|
export declare const classifyIngestHttpStatus: (status: number) => IngestRetryStrategy;
|