@gscdump/contracts 1.4.0 → 1.4.2
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/analytics.d.mts +5 -3
- package/dist/analytics.mjs +3 -3
- package/dist/archetypes.d.mts +1 -1
- package/dist/file-resolution.d.mts +155 -0
- package/dist/index.d.mts +6 -3
- package/dist/index.mjs +4 -2
- package/dist/onboarding.d.mts +113 -0
- package/dist/onboarding.mjs +122 -0
- package/dist/partner.d.mts +6 -4
- package/dist/partner.mjs +5 -3
- package/dist/routes.d.mts +88 -0
- package/dist/{_chunks/schemas.d.mts → schemas.d.mts} +1 -88
- package/dist/{_chunks/schemas.mjs → schemas.mjs} +3 -137
- package/dist/{_chunks/types.d.mts → types.d.mts} +3 -266
- package/dist/v1/browser.d.mts +437 -0
- package/dist/v1/browser.mjs +218 -0
- package/dist/v1/documents.d.mts +4 -0
- package/dist/v1/documents.mjs +227 -0
- package/dist/v1/http-core.d.mts +95 -0
- package/dist/v1/http-core.mjs +163 -0
- package/dist/v1/http.d.mts +4 -0
- package/dist/v1/http.mjs +4 -0
- package/dist/v1/index.d.mts +6 -12440
- package/dist/v1/index.mjs +6 -5107
- package/dist/v1/operations.d.mts +11713 -0
- package/dist/v1/operations.mjs +4095 -0
- package/dist/v1/realtime.d.mts +670 -0
- package/dist/v1/realtime.mjs +468 -0
- package/dist/v1/server.d.mts +6 -0
- package/dist/v1/server.mjs +6 -0
- package/dist/v1/version.d.mts +2 -0
- package/dist/v1/version.mjs +2 -0
- package/dist/webhook-constants.mjs +16 -0
- package/package.json +26 -1
- package/dist/{_chunks/endpoints.d.mts → endpoints.d.mts} +0 -0
- package/dist/{_chunks/endpoints.mjs → endpoints.mjs} +1 -1
- /package/dist/{_chunks/routes.mjs → routes.mjs} +0 -0
- /package/dist/{_chunks/webhook-constants.d.mts → webhook-constants.d.mts} +0 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import "./version.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const GSCDUMP_REALTIME_PROTOCOL_VERSION = 1;
|
|
4
|
+
const GSCDUMP_REALTIME_SUBPROTOCOL = "gscdump.v1";
|
|
5
|
+
const GSCDUMP_REALTIME_TICKET_PREFIX = "gscdump.ticket.v1";
|
|
6
|
+
const GSCDUMP_REALTIME_TICKET_ISSUER = "https://gscdump.com";
|
|
7
|
+
const GSCDUMP_REALTIME_TICKET_AUDIENCE = "https://gscdump.com/ws/v1";
|
|
8
|
+
const GSCDUMP_REALTIME_PING = "ping";
|
|
9
|
+
const GSCDUMP_REALTIME_PONG = "pong";
|
|
10
|
+
const GSCDUMP_REALTIME_TICKET_TTL_SECONDS = 60;
|
|
11
|
+
const GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS = 900;
|
|
12
|
+
const GSCDUMP_REALTIME_TICKET_POLICY = {
|
|
13
|
+
algorithm: "HMAC-SHA-256",
|
|
14
|
+
minimumSigningKeyBytes: 32,
|
|
15
|
+
jtiRandomBits: 128,
|
|
16
|
+
maxVerificationKeys: 2,
|
|
17
|
+
futureIssuedAtToleranceMs: 5e3,
|
|
18
|
+
expiryToleranceMs: 0,
|
|
19
|
+
rotationOverlapMs: 9e4,
|
|
20
|
+
maxBytes: 2048,
|
|
21
|
+
singleUse: true
|
|
22
|
+
};
|
|
23
|
+
const GSCDUMP_REALTIME_CONNECTION_POLICY = {
|
|
24
|
+
helloDeadlineMs: 1e4,
|
|
25
|
+
maxLifetimeMs: 9e5,
|
|
26
|
+
connectionRefreshBeforeExpiryMs: 3e4,
|
|
27
|
+
heartbeatIntervalMs: 25e3,
|
|
28
|
+
staleAfterMs: 75e3,
|
|
29
|
+
reconnectBaseDelayMs: 1e3,
|
|
30
|
+
reconnectMaxDelayMs: 3e4,
|
|
31
|
+
reconnectJitter: "equal"
|
|
32
|
+
};
|
|
33
|
+
const GSCDUMP_REALTIME_REPLAY_POLICY = {
|
|
34
|
+
maxAgeMs: 864e5,
|
|
35
|
+
maxEventsPerStream: 1e4
|
|
36
|
+
};
|
|
37
|
+
const GSCDUMP_REALTIME_LIMITS = {
|
|
38
|
+
clientFrameMaxBytes: 16384,
|
|
39
|
+
durableEventMaxBytes: 65536,
|
|
40
|
+
ephemeralEventMaxBytes: 16384,
|
|
41
|
+
outboundFrameMaxBytes: 262144,
|
|
42
|
+
batchMaxEvents: 20,
|
|
43
|
+
batchMaxBytes: 262144,
|
|
44
|
+
connectionAttachmentMaxBytes: 2048
|
|
45
|
+
};
|
|
46
|
+
const GSCDUMP_REALTIME_ACK_POLICY = {
|
|
47
|
+
softLagEvents: 100,
|
|
48
|
+
softLagBytes: 1048576,
|
|
49
|
+
hardLagEvents: 500,
|
|
50
|
+
hardLagBytes: 4194304,
|
|
51
|
+
hardLagCloseCode: 1013,
|
|
52
|
+
effectRetryBeforeUnsafeResync: 3
|
|
53
|
+
};
|
|
54
|
+
const GSCDUMP_REALTIME_CLOSE_CODES = {
|
|
55
|
+
normal: 1e3,
|
|
56
|
+
protocolError: 1002,
|
|
57
|
+
policyViolation: 1008,
|
|
58
|
+
internalError: 1011,
|
|
59
|
+
serviceRestart: 1012,
|
|
60
|
+
overloadedOrAckLag: 1013,
|
|
61
|
+
maximumLifetime: 4001
|
|
62
|
+
};
|
|
63
|
+
const REALTIME_V1_RESOURCE_TYPES = [
|
|
64
|
+
"partner.user",
|
|
65
|
+
"partner.team",
|
|
66
|
+
"user.sites",
|
|
67
|
+
"site.registration",
|
|
68
|
+
"site.lifecycle",
|
|
69
|
+
"site.analytics",
|
|
70
|
+
"site.sitemaps",
|
|
71
|
+
"site.indexing",
|
|
72
|
+
"site.auth"
|
|
73
|
+
];
|
|
74
|
+
const REALTIME_V1_EVENT_NAMES = [
|
|
75
|
+
"user.lifecycle.changed",
|
|
76
|
+
"site.lifecycle.changed",
|
|
77
|
+
"site.lifecycle.progress",
|
|
78
|
+
"site.analytics.ready",
|
|
79
|
+
"site.sitemaps.ready",
|
|
80
|
+
"site.indexing.ready",
|
|
81
|
+
"site.auth.failed",
|
|
82
|
+
"site.lifecycle.failed",
|
|
83
|
+
"site.registration.changed"
|
|
84
|
+
];
|
|
85
|
+
const REALTIME_V1_EVENT_SEMANTICS = {
|
|
86
|
+
"user.lifecycle.changed": {
|
|
87
|
+
delivery: "durable",
|
|
88
|
+
baseChanges: ["partner.user", "user.sites"]
|
|
89
|
+
},
|
|
90
|
+
"site.lifecycle.changed": {
|
|
91
|
+
delivery: "durable",
|
|
92
|
+
baseChanges: ["site.lifecycle"]
|
|
93
|
+
},
|
|
94
|
+
"site.lifecycle.progress": {
|
|
95
|
+
delivery: "ephemeral",
|
|
96
|
+
baseChanges: []
|
|
97
|
+
},
|
|
98
|
+
"site.analytics.ready": {
|
|
99
|
+
delivery: "durable",
|
|
100
|
+
baseChanges: ["site.analytics", "site.lifecycle"]
|
|
101
|
+
},
|
|
102
|
+
"site.sitemaps.ready": {
|
|
103
|
+
delivery: "durable",
|
|
104
|
+
baseChanges: ["site.sitemaps", "site.lifecycle"]
|
|
105
|
+
},
|
|
106
|
+
"site.indexing.ready": {
|
|
107
|
+
delivery: "durable",
|
|
108
|
+
baseChanges: ["site.indexing", "site.lifecycle"]
|
|
109
|
+
},
|
|
110
|
+
"site.auth.failed": {
|
|
111
|
+
delivery: "durable",
|
|
112
|
+
baseChanges: ["site.auth", "site.lifecycle"]
|
|
113
|
+
},
|
|
114
|
+
"site.lifecycle.failed": {
|
|
115
|
+
delivery: "durable",
|
|
116
|
+
baseChanges: ["site.lifecycle"]
|
|
117
|
+
},
|
|
118
|
+
"site.registration.changed": {
|
|
119
|
+
delivery: "durable",
|
|
120
|
+
baseChanges: ["site.registration", "user.sites"]
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
function createRealtimeV1Schemas() {
|
|
124
|
+
const sequence = z.string().regex(/^(0|[1-9]\d*)$/);
|
|
125
|
+
const opaquePublicId = z.string().regex(/^[\w-]+$/);
|
|
126
|
+
const publicUserId = z.string().regex(/^u_[\w-]+$/);
|
|
127
|
+
const publicPartnerId = z.string().regex(/^p_[\w-]+$/);
|
|
128
|
+
const publicTeamId = z.string().regex(/^t_[\w-]+$/);
|
|
129
|
+
const publicSiteId = z.string().regex(/^s_[\w-]+$/);
|
|
130
|
+
const publicPrincipalId = z.union([publicUserId, publicPartnerId]);
|
|
131
|
+
const publicResourceId = z.union([
|
|
132
|
+
publicUserId,
|
|
133
|
+
publicPartnerId,
|
|
134
|
+
publicTeamId,
|
|
135
|
+
publicSiteId
|
|
136
|
+
]);
|
|
137
|
+
const publicRequestId = z.string().regex(/^req_[\w-]+$/);
|
|
138
|
+
const publicEventId = z.string().regex(/^evt_[\w-]+$/);
|
|
139
|
+
const userStreamId = z.string().regex(/^user:u_[\w-]+$/);
|
|
140
|
+
const partnerStreamId = z.string().regex(/^partner:p_[\w-]+$/);
|
|
141
|
+
const streamId = z.union([userStreamId, partnerStreamId]);
|
|
142
|
+
const origin = z.url().refine((value) => {
|
|
143
|
+
const parsed = new URL(value);
|
|
144
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.origin === value;
|
|
145
|
+
}, "origin must be an exact HTTP(S) origin without a path, query, or fragment.");
|
|
146
|
+
const cursor = z.strictObject({
|
|
147
|
+
streamId,
|
|
148
|
+
sequence
|
|
149
|
+
});
|
|
150
|
+
const streamHead = z.strictObject({
|
|
151
|
+
streamId,
|
|
152
|
+
sequence
|
|
153
|
+
});
|
|
154
|
+
const ticketResponseClient = z.looseObject({
|
|
155
|
+
data: z.looseObject({
|
|
156
|
+
socketUrl: z.url().refine((value) => value.startsWith("wss://"), "socketUrl must use wss."),
|
|
157
|
+
protocol: z.literal(GSCDUMP_REALTIME_SUBPROTOCOL),
|
|
158
|
+
protocolVersion: z.literal(1),
|
|
159
|
+
ticket: z.string().max(GSCDUMP_REALTIME_TICKET_POLICY.maxBytes).regex(/^gscdump\.ticket\.v1\.[\w-]+\.[\w-]+$/),
|
|
160
|
+
expiresAt: z.iso.datetime(),
|
|
161
|
+
head: z.looseObject({
|
|
162
|
+
streamId,
|
|
163
|
+
sequence
|
|
164
|
+
}),
|
|
165
|
+
maxConnectionSeconds: z.literal(900)
|
|
166
|
+
}),
|
|
167
|
+
meta: z.looseObject({
|
|
168
|
+
requestId: publicRequestId,
|
|
169
|
+
surface: z.literal("realtime"),
|
|
170
|
+
version: z.literal("1.0")
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
const ticketRequest = z.strictObject({ origin: origin.optional() });
|
|
174
|
+
const ticketClaims = z.strictObject({
|
|
175
|
+
v: z.literal(1),
|
|
176
|
+
iss: z.literal(GSCDUMP_REALTIME_TICKET_ISSUER),
|
|
177
|
+
aud: z.literal(GSCDUMP_REALTIME_TICKET_AUDIENCE),
|
|
178
|
+
kid: z.string().regex(/^[\w-]{1,128}$/),
|
|
179
|
+
jti: z.string().regex(/^[\w-]{22,}$/),
|
|
180
|
+
iat: z.number().int().nonnegative(),
|
|
181
|
+
exp: z.number().int().positive(),
|
|
182
|
+
connectionExpiresAt: z.number().int().positive(),
|
|
183
|
+
principalClass: z.enum(["user_key", "partner_key"]),
|
|
184
|
+
principalPublicId: publicPrincipalId,
|
|
185
|
+
streamId,
|
|
186
|
+
origin: origin.nullable()
|
|
187
|
+
}).superRefine((claims, context) => {
|
|
188
|
+
if (claims.exp <= claims.iat || claims.exp - claims.iat > 60) context.addIssue({
|
|
189
|
+
code: "custom",
|
|
190
|
+
message: `exp must be after iat and no more than 60 seconds later.`,
|
|
191
|
+
path: ["exp"]
|
|
192
|
+
});
|
|
193
|
+
if (claims.connectionExpiresAt <= claims.iat || claims.connectionExpiresAt - claims.iat > 900) context.addIssue({
|
|
194
|
+
code: "custom",
|
|
195
|
+
message: `connectionExpiresAt must be after iat and no more than 900 seconds later.`,
|
|
196
|
+
path: ["connectionExpiresAt"]
|
|
197
|
+
});
|
|
198
|
+
if (claims.connectionExpiresAt < claims.exp) context.addIssue({
|
|
199
|
+
code: "custom",
|
|
200
|
+
message: "connectionExpiresAt cannot be earlier than exp.",
|
|
201
|
+
path: ["connectionExpiresAt"]
|
|
202
|
+
});
|
|
203
|
+
const expectedStream = claims.principalClass === "user_key" ? `user:${claims.principalPublicId}` : `partner:${claims.principalPublicId}`;
|
|
204
|
+
if (claims.streamId !== expectedStream) context.addIssue({
|
|
205
|
+
code: "custom",
|
|
206
|
+
message: "streamId must be the exact stream inferred from principalClass and principalPublicId.",
|
|
207
|
+
path: ["streamId"]
|
|
208
|
+
});
|
|
209
|
+
if (claims.principalClass === "user_key" && !claims.principalPublicId.startsWith("u_")) context.addIssue({
|
|
210
|
+
code: "custom",
|
|
211
|
+
message: "A user principal requires a user public ID.",
|
|
212
|
+
path: ["principalPublicId"]
|
|
213
|
+
});
|
|
214
|
+
if (claims.principalClass === "partner_key" && !claims.principalPublicId.startsWith("p_")) context.addIssue({
|
|
215
|
+
code: "custom",
|
|
216
|
+
message: "A partner principal requires a partner public ID.",
|
|
217
|
+
path: ["principalPublicId"]
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
const knownResourceType = z.enum(REALTIME_V1_RESOURCE_TYPES);
|
|
221
|
+
const resourceChange = z.strictObject({
|
|
222
|
+
type: z.string().regex(/^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*)+$/),
|
|
223
|
+
id: opaquePublicId,
|
|
224
|
+
kind: z.enum([
|
|
225
|
+
"created",
|
|
226
|
+
"updated",
|
|
227
|
+
"deleted"
|
|
228
|
+
])
|
|
229
|
+
}).superRefine((change, context) => {
|
|
230
|
+
const prefix = change.type === "partner.user" || change.type === "user.sites" ? "u_" : change.type === "partner.team" ? "t_" : REALTIME_V1_RESOURCE_TYPES.includes(change.type) && change.type.startsWith("site.") ? "s_" : null;
|
|
231
|
+
if (prefix && !change.id.startsWith(prefix)) context.addIssue({
|
|
232
|
+
code: "custom",
|
|
233
|
+
message: `${change.type} requires an opaque ${prefix} public ID.`,
|
|
234
|
+
path: ["id"]
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
const subject = z.discriminatedUnion("type", [
|
|
238
|
+
z.strictObject({
|
|
239
|
+
type: z.literal("partner"),
|
|
240
|
+
id: publicPartnerId
|
|
241
|
+
}),
|
|
242
|
+
z.strictObject({
|
|
243
|
+
type: z.literal("team"),
|
|
244
|
+
id: publicTeamId
|
|
245
|
+
}),
|
|
246
|
+
z.strictObject({
|
|
247
|
+
type: z.literal("user"),
|
|
248
|
+
id: publicUserId
|
|
249
|
+
}),
|
|
250
|
+
z.strictObject({
|
|
251
|
+
type: z.literal("site"),
|
|
252
|
+
id: publicSiteId
|
|
253
|
+
})
|
|
254
|
+
]);
|
|
255
|
+
const eventBase = {
|
|
256
|
+
type: z.literal("event"),
|
|
257
|
+
protocolVersion: z.literal(1),
|
|
258
|
+
eventVersion: z.number().int().positive(),
|
|
259
|
+
id: publicEventId,
|
|
260
|
+
name: z.string().regex(/^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*)+$/),
|
|
261
|
+
subject,
|
|
262
|
+
changes: z.array(resourceChange),
|
|
263
|
+
occurredAt: z.iso.datetime(),
|
|
264
|
+
correlationId: publicRequestId.nullable(),
|
|
265
|
+
data: z.json()
|
|
266
|
+
};
|
|
267
|
+
const durableEvent = z.strictObject({
|
|
268
|
+
...eventBase,
|
|
269
|
+
cursor,
|
|
270
|
+
changes: z.array(resourceChange).min(1),
|
|
271
|
+
delivery: z.literal("durable")
|
|
272
|
+
}).superRefine((event, context) => {
|
|
273
|
+
const semantics = REALTIME_V1_EVENT_SEMANTICS[event.name];
|
|
274
|
+
if (semantics?.delivery === "ephemeral") context.addIssue({
|
|
275
|
+
code: "custom",
|
|
276
|
+
message: `${event.name} must use ephemeral delivery.`,
|
|
277
|
+
path: ["delivery"]
|
|
278
|
+
});
|
|
279
|
+
if (semantics) {
|
|
280
|
+
for (const requiredType of semantics.baseChanges) if (!event.changes.some((change) => change.type === requiredType)) context.addIssue({
|
|
281
|
+
code: "custom",
|
|
282
|
+
message: `${event.name} requires a ${requiredType} base change.`,
|
|
283
|
+
path: ["changes"]
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
const ephemeralEvent = z.strictObject({
|
|
288
|
+
...eventBase,
|
|
289
|
+
cursor: z.null(),
|
|
290
|
+
changes: z.array(resourceChange).max(0),
|
|
291
|
+
delivery: z.literal("ephemeral")
|
|
292
|
+
}).superRefine((event, context) => {
|
|
293
|
+
if (REALTIME_V1_EVENT_SEMANTICS[event.name]?.delivery === "durable") context.addIssue({
|
|
294
|
+
code: "custom",
|
|
295
|
+
message: `${event.name} must use durable delivery.`,
|
|
296
|
+
path: ["delivery"]
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
const event = z.union([durableEvent, ephemeralEvent]);
|
|
300
|
+
const helloFrame = z.strictObject({
|
|
301
|
+
type: z.literal("hello"),
|
|
302
|
+
protocolVersion: z.literal(1),
|
|
303
|
+
sdkVersion: z.string().min(1),
|
|
304
|
+
resume: cursor.nullable()
|
|
305
|
+
});
|
|
306
|
+
const ackFrame = z.strictObject({
|
|
307
|
+
type: z.literal("ack"),
|
|
308
|
+
cursor
|
|
309
|
+
});
|
|
310
|
+
const readyFrame = z.strictObject({
|
|
311
|
+
type: z.literal("ready"),
|
|
312
|
+
protocolVersion: z.literal(1),
|
|
313
|
+
connectionId: z.string().regex(/^conn_[\w-]+$/),
|
|
314
|
+
streamId,
|
|
315
|
+
replayFloor: streamHead,
|
|
316
|
+
head: streamHead,
|
|
317
|
+
limits: z.strictObject({
|
|
318
|
+
maxBatchEvents: z.number().int().positive().max(GSCDUMP_REALTIME_LIMITS.batchMaxEvents),
|
|
319
|
+
maxUnackedEvents: z.number().int().positive().max(GSCDUMP_REALTIME_ACK_POLICY.hardLagEvents)
|
|
320
|
+
}),
|
|
321
|
+
heartbeat: z.strictObject({
|
|
322
|
+
ping: z.literal(GSCDUMP_REALTIME_PING),
|
|
323
|
+
pong: z.literal(GSCDUMP_REALTIME_PONG)
|
|
324
|
+
}),
|
|
325
|
+
expiresAt: z.iso.datetime()
|
|
326
|
+
}).superRefine((frame, context) => {
|
|
327
|
+
if (frame.head.streamId !== frame.streamId || frame.replayFloor.streamId !== frame.streamId) context.addIssue({
|
|
328
|
+
code: "custom",
|
|
329
|
+
message: "ready head and replayFloor must match streamId."
|
|
330
|
+
});
|
|
331
|
+
if (BigInt(frame.replayFloor.sequence) > BigInt(frame.head.sequence)) context.addIssue({
|
|
332
|
+
code: "custom",
|
|
333
|
+
message: "replayFloor cannot be ahead of head.",
|
|
334
|
+
path: ["replayFloor"]
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
const replayBeginFrame = z.strictObject({
|
|
338
|
+
type: z.literal("replay.begin"),
|
|
339
|
+
after: cursor.nullable(),
|
|
340
|
+
through: cursor
|
|
341
|
+
}).superRefine((frame, context) => {
|
|
342
|
+
if (!frame.after) return;
|
|
343
|
+
if (frame.after.streamId !== frame.through.streamId) context.addIssue({
|
|
344
|
+
code: "custom",
|
|
345
|
+
message: "Replay cursors must belong to one stream.",
|
|
346
|
+
path: ["through"]
|
|
347
|
+
});
|
|
348
|
+
if (BigInt(frame.after.sequence) > BigInt(frame.through.sequence)) context.addIssue({
|
|
349
|
+
code: "custom",
|
|
350
|
+
message: "Replay through cannot be behind after.",
|
|
351
|
+
path: ["through"]
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
const replayEndFrame = z.strictObject({
|
|
355
|
+
type: z.literal("replay.end"),
|
|
356
|
+
through: cursor
|
|
357
|
+
});
|
|
358
|
+
const batchFrame = z.strictObject({
|
|
359
|
+
type: z.literal("batch"),
|
|
360
|
+
events: z.array(durableEvent).min(1).max(GSCDUMP_REALTIME_LIMITS.batchMaxEvents)
|
|
361
|
+
}).superRefine((frame, context) => {
|
|
362
|
+
const first = frame.events[0];
|
|
363
|
+
if (!first) return;
|
|
364
|
+
for (const [index, current] of frame.events.entries()) {
|
|
365
|
+
if (current.cursor.streamId !== first.cursor.streamId) context.addIssue({
|
|
366
|
+
code: "custom",
|
|
367
|
+
message: "A batch must contain events from one exact stream.",
|
|
368
|
+
path: [
|
|
369
|
+
"events",
|
|
370
|
+
index,
|
|
371
|
+
"cursor",
|
|
372
|
+
"streamId"
|
|
373
|
+
]
|
|
374
|
+
});
|
|
375
|
+
const previous = frame.events[index - 1];
|
|
376
|
+
if (previous && BigInt(current.cursor.sequence) !== BigInt(previous.cursor.sequence) + 1n) context.addIssue({
|
|
377
|
+
code: "custom",
|
|
378
|
+
message: "Batch cursors must be contiguous and ordered.",
|
|
379
|
+
path: [
|
|
380
|
+
"events",
|
|
381
|
+
index,
|
|
382
|
+
"cursor",
|
|
383
|
+
"sequence"
|
|
384
|
+
]
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
const resyncRequiredFrame = z.strictObject({
|
|
389
|
+
type: z.literal("resync.required"),
|
|
390
|
+
reason: z.enum([
|
|
391
|
+
"cursor_expired",
|
|
392
|
+
"retention_gap",
|
|
393
|
+
"sequence_gap",
|
|
394
|
+
"stream_mismatch"
|
|
395
|
+
]),
|
|
396
|
+
scope: z.strictObject({
|
|
397
|
+
type: z.literal("stream"),
|
|
398
|
+
streamId
|
|
399
|
+
}),
|
|
400
|
+
resumeAfter: cursor
|
|
401
|
+
}).superRefine((frame, context) => {
|
|
402
|
+
if (frame.scope.streamId !== frame.resumeAfter.streamId) context.addIssue({
|
|
403
|
+
code: "custom",
|
|
404
|
+
message: "resync.required scope and resumeAfter must identify one exact stream.",
|
|
405
|
+
path: ["resumeAfter", "streamId"]
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
const realtimeErrorFrame = z.strictObject({
|
|
409
|
+
type: z.literal("error"),
|
|
410
|
+
error: z.strictObject({
|
|
411
|
+
code: z.enum([
|
|
412
|
+
"invalid_frame",
|
|
413
|
+
"protocol_mismatch",
|
|
414
|
+
"policy_violation",
|
|
415
|
+
"overloaded",
|
|
416
|
+
"internal_error"
|
|
417
|
+
]),
|
|
418
|
+
message: z.string().min(1),
|
|
419
|
+
retryable: z.boolean(),
|
|
420
|
+
retryAfter: z.number().int().nonnegative().optional()
|
|
421
|
+
})
|
|
422
|
+
});
|
|
423
|
+
return {
|
|
424
|
+
opaquePublicId,
|
|
425
|
+
userStreamId,
|
|
426
|
+
partnerStreamId,
|
|
427
|
+
publicUserId,
|
|
428
|
+
publicPartnerId,
|
|
429
|
+
publicTeamId,
|
|
430
|
+
publicSiteId,
|
|
431
|
+
publicPrincipalId,
|
|
432
|
+
publicResourceId,
|
|
433
|
+
publicRequestId,
|
|
434
|
+
publicEventId,
|
|
435
|
+
sequence,
|
|
436
|
+
streamId,
|
|
437
|
+
cursor,
|
|
438
|
+
streamHead,
|
|
439
|
+
ticketResponseClient,
|
|
440
|
+
ticketRequest,
|
|
441
|
+
ticketClaims,
|
|
442
|
+
knownResourceType,
|
|
443
|
+
resourceChange,
|
|
444
|
+
subject,
|
|
445
|
+
durableEvent,
|
|
446
|
+
ephemeralEvent,
|
|
447
|
+
event,
|
|
448
|
+
helloFrame,
|
|
449
|
+
ackFrame,
|
|
450
|
+
readyFrame,
|
|
451
|
+
replayBeginFrame,
|
|
452
|
+
replayEndFrame,
|
|
453
|
+
batchFrame,
|
|
454
|
+
resyncRequiredFrame,
|
|
455
|
+
realtimeErrorFrame,
|
|
456
|
+
clientFrame: z.union([helloFrame, ackFrame]),
|
|
457
|
+
serverFrame: z.union([
|
|
458
|
+
readyFrame,
|
|
459
|
+
replayBeginFrame,
|
|
460
|
+
replayEndFrame,
|
|
461
|
+
event,
|
|
462
|
+
batchFrame,
|
|
463
|
+
resyncRequiredFrame,
|
|
464
|
+
realtimeErrorFrame
|
|
465
|
+
])
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
export { GSCDUMP_REALTIME_ACK_POLICY, GSCDUMP_REALTIME_CLOSE_CODES, GSCDUMP_REALTIME_CONNECTION_POLICY, GSCDUMP_REALTIME_LIMITS, GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS, GSCDUMP_REALTIME_PING, GSCDUMP_REALTIME_PONG, GSCDUMP_REALTIME_PROTOCOL_VERSION, GSCDUMP_REALTIME_REPLAY_POLICY, GSCDUMP_REALTIME_SUBPROTOCOL, GSCDUMP_REALTIME_TICKET_AUDIENCE, GSCDUMP_REALTIME_TICKET_ISSUER, GSCDUMP_REALTIME_TICKET_POLICY, GSCDUMP_REALTIME_TICKET_PREFIX, GSCDUMP_REALTIME_TICKET_TTL_SECONDS, REALTIME_V1_EVENT_NAMES, REALTIME_V1_EVENT_SEMANTICS, REALTIME_V1_RESOURCE_TYPES, createRealtimeV1Schemas };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { GSCDUMP_HTTP_V1_VERSION } from "./version.mjs";
|
|
2
|
+
import { CompatibleResponseSchema, HTTP_V1_CREDENTIALS, HTTP_V1_CREDENTIAL_SCOPES, HTTP_V1_ERROR_CODES, HTTP_V1_METHODS, HTTP_V1_SCOPES, HTTP_V1_SURFACES, HttpV1Credential, HttpV1ErrorCode, HttpV1Method, HttpV1OperationDefinition, HttpV1OwnershipRule, HttpV1RequestSchemas, HttpV1ResourceReference, HttpV1ResourceType, HttpV1Scope, HttpV1Semantics, HttpV1Surface, HttpV1SurfaceName, HttpV1Visibility, buildHttpOperationPath, defineHttpOperation, defineHttpSurface, defineResponseObject, defineSuccessResponse } from "./http-core.mjs";
|
|
3
|
+
import { GSCDUMP_REALTIME_ACK_POLICY, GSCDUMP_REALTIME_CLOSE_CODES, GSCDUMP_REALTIME_CONNECTION_POLICY, GSCDUMP_REALTIME_LIMITS, GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS, GSCDUMP_REALTIME_PING, GSCDUMP_REALTIME_PONG, GSCDUMP_REALTIME_PROTOCOL_VERSION, GSCDUMP_REALTIME_REPLAY_POLICY, GSCDUMP_REALTIME_SUBPROTOCOL, GSCDUMP_REALTIME_TICKET_AUDIENCE, GSCDUMP_REALTIME_TICKET_ISSUER, GSCDUMP_REALTIME_TICKET_POLICY, GSCDUMP_REALTIME_TICKET_PREFIX, GSCDUMP_REALTIME_TICKET_TTL_SECONDS, REALTIME_V1_EVENT_NAMES, REALTIME_V1_EVENT_SEMANTICS, REALTIME_V1_RESOURCE_TYPES, RealtimeTicketV1Response, RealtimeV1ClientFrame, RealtimeV1Cursor, RealtimeV1Event, RealtimeV1ResourceChange, RealtimeV1Schemas, RealtimeV1ServerFrame, RealtimeV1StreamHead, RealtimeV1StreamId, RealtimeV1TicketClaims, RealtimeV1TicketRequest, createRealtimeV1Schemas } from "./realtime.mjs";
|
|
4
|
+
import { AnalyticsReportDetailV1Request, AnalyticsReportDetailV1Response, AnalyticsReportV1Request, AnalyticsReportV1Response, AnalyticsRowsV1Request, AnalyticsRowsV1Response, GscdumpV1ErrorEnvelope, GscdumpV1Protocol, GscdumpV1RequestMetadata, PartnerAnalysisBundleV1Response, PartnerAnalysisV1Response, PartnerAvailableSitesV1Response, PartnerIndexingDiagnosticsV1Response, PartnerIndexingUrlsV1Response, PartnerIndexingV1Response, PartnerSiteDeletionV1Response, PartnerSiteRegistrationV1Response, PartnerSitemapChangesV1Response, PartnerSitemapsV1Response, PartnerUserLifecycleV1Response, createGscdumpV1Protocol } from "./operations.mjs";
|
|
5
|
+
import "./http.mjs";
|
|
6
|
+
export { AnalyticsReportDetailV1Request, AnalyticsReportDetailV1Response, AnalyticsReportV1Request, AnalyticsReportV1Response, AnalyticsRowsV1Request, AnalyticsRowsV1Response, CompatibleResponseSchema, GSCDUMP_HTTP_V1_VERSION, GSCDUMP_REALTIME_ACK_POLICY, GSCDUMP_REALTIME_CLOSE_CODES, GSCDUMP_REALTIME_CONNECTION_POLICY, GSCDUMP_REALTIME_LIMITS, GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS, GSCDUMP_REALTIME_PING, GSCDUMP_REALTIME_PONG, GSCDUMP_REALTIME_PROTOCOL_VERSION, GSCDUMP_REALTIME_REPLAY_POLICY, GSCDUMP_REALTIME_SUBPROTOCOL, GSCDUMP_REALTIME_TICKET_AUDIENCE, GSCDUMP_REALTIME_TICKET_ISSUER, GSCDUMP_REALTIME_TICKET_POLICY, GSCDUMP_REALTIME_TICKET_PREFIX, GSCDUMP_REALTIME_TICKET_TTL_SECONDS, GscdumpV1ErrorEnvelope, GscdumpV1Protocol, GscdumpV1RequestMetadata, HTTP_V1_CREDENTIALS, HTTP_V1_CREDENTIAL_SCOPES, HTTP_V1_ERROR_CODES, HTTP_V1_METHODS, HTTP_V1_SCOPES, HTTP_V1_SURFACES, HttpV1Credential, HttpV1ErrorCode, HttpV1Method, HttpV1OperationDefinition, HttpV1OwnershipRule, HttpV1RequestSchemas, HttpV1ResourceReference, HttpV1ResourceType, HttpV1Scope, HttpV1Semantics, HttpV1Surface, HttpV1SurfaceName, HttpV1Visibility, PartnerAnalysisBundleV1Response, PartnerAnalysisV1Response, PartnerAvailableSitesV1Response, PartnerIndexingDiagnosticsV1Response, PartnerIndexingUrlsV1Response, PartnerIndexingV1Response, PartnerSiteDeletionV1Response, PartnerSiteRegistrationV1Response, PartnerSitemapChangesV1Response, PartnerSitemapsV1Response, PartnerUserLifecycleV1Response, REALTIME_V1_EVENT_NAMES, REALTIME_V1_EVENT_SEMANTICS, REALTIME_V1_RESOURCE_TYPES, RealtimeTicketV1Response, RealtimeV1ClientFrame, RealtimeV1Cursor, RealtimeV1Event, RealtimeV1ResourceChange, RealtimeV1Schemas, RealtimeV1ServerFrame, RealtimeV1StreamHead, RealtimeV1StreamId, RealtimeV1TicketClaims, RealtimeV1TicketRequest, buildHttpOperationPath, createGscdumpV1Protocol, createRealtimeV1Schemas, defineHttpOperation, defineHttpSurface, defineResponseObject, defineSuccessResponse };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { GSCDUMP_HTTP_V1_VERSION } from "./version.mjs";
|
|
2
|
+
import { HTTP_V1_CREDENTIALS, HTTP_V1_CREDENTIAL_SCOPES, HTTP_V1_ERROR_CODES, HTTP_V1_METHODS, HTTP_V1_SCOPES, HTTP_V1_SURFACES, buildHttpOperationPath, defineHttpOperation, defineHttpSurface, defineResponseObject, defineSuccessResponse } from "./http-core.mjs";
|
|
3
|
+
import { GSCDUMP_REALTIME_ACK_POLICY, GSCDUMP_REALTIME_CLOSE_CODES, GSCDUMP_REALTIME_CONNECTION_POLICY, GSCDUMP_REALTIME_LIMITS, GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS, GSCDUMP_REALTIME_PING, GSCDUMP_REALTIME_PONG, GSCDUMP_REALTIME_PROTOCOL_VERSION, GSCDUMP_REALTIME_REPLAY_POLICY, GSCDUMP_REALTIME_SUBPROTOCOL, GSCDUMP_REALTIME_TICKET_AUDIENCE, GSCDUMP_REALTIME_TICKET_ISSUER, GSCDUMP_REALTIME_TICKET_POLICY, GSCDUMP_REALTIME_TICKET_PREFIX, GSCDUMP_REALTIME_TICKET_TTL_SECONDS, REALTIME_V1_EVENT_NAMES, REALTIME_V1_EVENT_SEMANTICS, REALTIME_V1_RESOURCE_TYPES, createRealtimeV1Schemas } from "./realtime.mjs";
|
|
4
|
+
import { createGscdumpV1Protocol } from "./operations.mjs";
|
|
5
|
+
import "./http.mjs";
|
|
6
|
+
export { GSCDUMP_HTTP_V1_VERSION, GSCDUMP_REALTIME_ACK_POLICY, GSCDUMP_REALTIME_CLOSE_CODES, GSCDUMP_REALTIME_CONNECTION_POLICY, GSCDUMP_REALTIME_LIMITS, GSCDUMP_REALTIME_MAX_CONNECTION_SECONDS, GSCDUMP_REALTIME_PING, GSCDUMP_REALTIME_PONG, GSCDUMP_REALTIME_PROTOCOL_VERSION, GSCDUMP_REALTIME_REPLAY_POLICY, GSCDUMP_REALTIME_SUBPROTOCOL, GSCDUMP_REALTIME_TICKET_AUDIENCE, GSCDUMP_REALTIME_TICKET_ISSUER, GSCDUMP_REALTIME_TICKET_POLICY, GSCDUMP_REALTIME_TICKET_PREFIX, GSCDUMP_REALTIME_TICKET_TTL_SECONDS, HTTP_V1_CREDENTIALS, HTTP_V1_CREDENTIAL_SCOPES, HTTP_V1_ERROR_CODES, HTTP_V1_METHODS, HTTP_V1_SCOPES, HTTP_V1_SURFACES, REALTIME_V1_EVENT_NAMES, REALTIME_V1_EVENT_SEMANTICS, REALTIME_V1_RESOURCE_TYPES, buildHttpOperationPath, createGscdumpV1Protocol, createRealtimeV1Schemas, defineHttpOperation, defineHttpSurface, defineResponseObject, defineSuccessResponse };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const WEBHOOK_CONTRACT_VERSION = "2026-05-11";
|
|
2
|
+
const WEBHOOK_SIGNATURE_HEADER = "X-GSCDump-Signature";
|
|
3
|
+
const WEBHOOK_EVENT_HEADER = "X-GSCDump-Event";
|
|
4
|
+
const WEBHOOK_DELIVERY_HEADER = "X-GSCDump-Delivery";
|
|
5
|
+
const WEBHOOK_CONTRACT_VERSION_HEADER = "X-GSCDump-Contract-Version";
|
|
6
|
+
const WEBHOOK_TIMESTAMP_HEADER = "X-GSCDump-Timestamp";
|
|
7
|
+
const CANONICAL_WEBHOOK_EVENTS = [
|
|
8
|
+
"user.lifecycle.changed",
|
|
9
|
+
"site.lifecycle.changed",
|
|
10
|
+
"site.analytics.ready",
|
|
11
|
+
"site.indexing.ready",
|
|
12
|
+
"site.auth.failed",
|
|
13
|
+
"job.failed"
|
|
14
|
+
];
|
|
15
|
+
const VALID_WEBHOOK_EVENTS = CANONICAL_WEBHOOK_EVENTS;
|
|
16
|
+
export { CANONICAL_WEBHOOK_EVENTS, VALID_WEBHOOK_EVENTS, WEBHOOK_CONTRACT_VERSION, WEBHOOK_CONTRACT_VERSION_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_TIMESTAMP_HEADER };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/contracts",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.2",
|
|
5
5
|
"description": "Shared gscdump.com API, webhook, realtime, and lifecycle contracts.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -45,6 +45,31 @@
|
|
|
45
45
|
"types": "./dist/v1/index.d.mts",
|
|
46
46
|
"import": "./dist/v1/index.mjs",
|
|
47
47
|
"default": "./dist/v1/index.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./v1/browser": {
|
|
50
|
+
"types": "./dist/v1/browser.d.mts",
|
|
51
|
+
"import": "./dist/v1/browser.mjs",
|
|
52
|
+
"default": "./dist/v1/browser.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./v1/documents": {
|
|
55
|
+
"types": "./dist/v1/documents.d.mts",
|
|
56
|
+
"import": "./dist/v1/documents.mjs",
|
|
57
|
+
"default": "./dist/v1/documents.mjs"
|
|
58
|
+
},
|
|
59
|
+
"./v1/http": {
|
|
60
|
+
"types": "./dist/v1/http.d.mts",
|
|
61
|
+
"import": "./dist/v1/http.mjs",
|
|
62
|
+
"default": "./dist/v1/http.mjs"
|
|
63
|
+
},
|
|
64
|
+
"./v1/realtime": {
|
|
65
|
+
"types": "./dist/v1/realtime.d.mts",
|
|
66
|
+
"import": "./dist/v1/realtime.mjs",
|
|
67
|
+
"default": "./dist/v1/realtime.mjs"
|
|
68
|
+
},
|
|
69
|
+
"./v1/server": {
|
|
70
|
+
"types": "./dist/v1/server.d.mts",
|
|
71
|
+
"import": "./dist/v1/server.mjs",
|
|
72
|
+
"default": "./dist/v1/server.mjs"
|
|
48
73
|
}
|
|
49
74
|
},
|
|
50
75
|
"main": "./dist/index.mjs",
|
|
File without changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { analyticsEndpointSchemas, partnerControlEndpointSchemas } from "./schemas.mjs";
|
|
2
1
|
import { analyticsRoutes, partnerRoutes } from "./routes.mjs";
|
|
2
|
+
import { analyticsEndpointSchemas, partnerControlEndpointSchemas } from "./schemas.mjs";
|
|
3
3
|
function defineEndpoint(method, path, schema) {
|
|
4
4
|
return {
|
|
5
5
|
method,
|
|
File without changes
|
|
File without changes
|