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