@domino-sdk/relay 1.61.0 → 1.63.0

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 (88) hide show
  1. package/CHANGELOG.md +276 -8
  2. package/README.md +3 -2
  3. package/dist/{schema-CZ6Rj0ZF.d.ts → accounts-nz3mzfRQ.d.ts} +3146 -1765
  4. package/dist/action-9Xl0StBg.d.ts +33 -0
  5. package/dist/{attempt-captures-DYnJVkfg.d.ts → attempt-captures-DMi8oR9T.d.ts} +1 -1
  6. package/dist/authoring.d.ts +171 -49
  7. package/dist/authoring.js +158 -49
  8. package/dist/{automatic-outcomes-If88LR9f.d.ts → automatic-outcomes-C_LLQU1p.d.ts} +15 -1
  9. package/dist/avatar.d.ts +1 -1
  10. package/dist/browser.d.ts +15 -11
  11. package/dist/browser.js +18 -12
  12. package/dist/capability-error-CuI_F7yM.d.ts +296 -0
  13. package/dist/{pages-K7-KjSXw.d.ts → catalog-BaTOKpNw.d.ts} +56 -567
  14. package/dist/{chunk-XBV2CK2H.js → chunk-3RFP6GT5.js} +15 -3
  15. package/dist/{chunk-VURRFVNP.js → chunk-4GQW43UU.js} +239 -361
  16. package/dist/chunk-4NOFSGAL.js +320 -0
  17. package/dist/{chunk-24I4R732.js → chunk-5XLZ34PV.js} +34 -19
  18. package/dist/{chunk-L77O64I4.js → chunk-7X67QLPB.js} +43 -43
  19. package/dist/{chunk-RHBS5FJL.js → chunk-7Z4SZ6YM.js} +3 -3
  20. package/dist/{chunk-QEAS4ZGS.js → chunk-AQOL3SK5.js} +1 -1
  21. package/dist/chunk-EHUSD3O2.js +377 -0
  22. package/dist/chunk-FO2LCZTL.js +19 -0
  23. package/dist/{chunk-DYXDZFKA.js → chunk-FU5CGNTR.js} +166 -178
  24. package/dist/chunk-FWLQ5XCS.js +21 -0
  25. package/dist/chunk-GLH6MEI2.js +193 -0
  26. package/dist/chunk-ICXZZNPS.js +199 -0
  27. package/dist/{chunk-ZDJLPN4L.js → chunk-ID3BZXFZ.js} +2696 -2693
  28. package/dist/chunk-KP2MCX3R.js +587 -0
  29. package/dist/{chunk-SKGTNTLF.js → chunk-LZWXCBUB.js} +213 -297
  30. package/dist/chunk-MTKRIQEU.js +31 -0
  31. package/dist/{chunk-4OC7REYX.js → chunk-MWMCQLCG.js} +3 -3
  32. package/dist/{chunk-PPB7HALD.js → chunk-N4BDKS6Y.js} +27 -26
  33. package/dist/{chunk-5I54XBK2.js → chunk-N4LNEGQX.js} +2 -2
  34. package/dist/chunk-NQDEWJWE.js +554 -0
  35. package/dist/chunk-QR6HH4DI.js +508 -0
  36. package/dist/chunk-TLSQETTY.js +41 -0
  37. package/dist/{chunk-MHPKEVEW.js → chunk-U66GUVSG.js} +7 -2
  38. package/dist/{chunk-KDR2VAJP.js → chunk-UYVJZR33.js} +2 -2
  39. package/dist/chunk-UZ765UGH.js +18 -0
  40. package/dist/{chunk-7A4J67ZL.js → chunk-VWQGWGCH.js} +7 -7
  41. package/dist/chunk-W7YSMSGC.js +725 -0
  42. package/dist/{client-C51w7fMb.d.ts → client-DHmG7rn6.d.ts} +126 -93
  43. package/dist/{announcements-CHx3-HBw.d.ts → dashboards-CLemT6kj.d.ts} +14 -137
  44. package/dist/{deployments-kWoHFaqj.d.ts → deployments-DTULi7dF.d.ts} +450 -18
  45. package/dist/identity-integration-DOeNZaxF.d.ts +1271 -0
  46. package/dist/index.d.ts +13 -11
  47. package/dist/index.js +16 -11
  48. package/dist/internal.d.ts +29 -13
  49. package/dist/internal.js +57 -17
  50. package/dist/{integrations-B3y36OaB.d.ts → limits-kNzYdZ00.d.ts} +464 -53
  51. package/dist/{offers-BoV4ryUc.d.ts → offers-CYeN_I0Y.d.ts} +22 -4
  52. package/dist/{participant-activity-DHL8QYks.d.ts → participant-activity-D-Drp24G.d.ts} +16 -3
  53. package/dist/portal-proxy.d.ts +75 -2
  54. package/dist/portal-proxy.js +153 -25
  55. package/dist/react/index.d.ts +214 -27
  56. package/dist/react/index.js +196 -42
  57. package/dist/{action-DBzILFx9.d.ts → request-error-D_dUPLwo.d.ts} +1 -31
  58. package/dist/reward-deliveries-drp-x1G-.d.ts +782 -0
  59. package/dist/runtime/authoring.js +1 -1
  60. package/dist/runtime/chunks/UGDV5W4N.js +1 -0
  61. package/dist/runtime/manifest.json +3 -3
  62. package/dist/runtime/schema.js +1 -1
  63. package/dist/schema.d.ts +330 -31
  64. package/dist/schema.js +147 -91
  65. package/dist/server/index.d.ts +14 -12
  66. package/dist/server/index.js +6425 -6260
  67. package/dist/sign-in-providers-B1Q9eDRm.d.ts +44 -0
  68. package/dist/submission-input-DZCbjQUH.d.ts +343 -0
  69. package/dist/{telegram-browser-BUceZIGZ.d.ts → telegram-browser-NL0Asmsi.d.ts} +46 -6
  70. package/dist/telegram.d.ts +64 -0
  71. package/dist/telegram.js +23 -0
  72. package/dist/testing.d.ts +326 -27
  73. package/dist/testing.js +440 -90
  74. package/dist/tracker-data-esm3WG8R.d.ts +1881 -0
  75. package/dist/{transport-BrX9pIGN.d.ts → transport-Czht_irp.d.ts} +43483 -38512
  76. package/dist/{wallet-CIqFoxdm.d.ts → wallet-B7e06v4m.d.ts} +32 -9
  77. package/package.json +5 -1
  78. package/dist/accounts-DoabriBX.d.ts +0 -306
  79. package/dist/capability-error-DufwG3G0.d.ts +0 -159
  80. package/dist/chunk-3Y3L2F54.js +0 -982
  81. package/dist/chunk-DHXDBAJF.js +0 -544
  82. package/dist/chunk-EN3M5Z4J.js +0 -13
  83. package/dist/chunk-QNUHWK7R.js +0 -602
  84. package/dist/chunk-SE4PFJPT.js +0 -247
  85. package/dist/groups-CqcA2Ycs.d.ts +0 -2827
  86. package/dist/runtime/chunks/5QVFB4TU.js +0 -1
  87. package/dist/submission-input-C54Q8yAD.d.ts +0 -146
  88. package/dist/x-D1PGi8Sq.d.ts +0 -331
@@ -0,0 +1,554 @@
1
+ import {
2
+ createHttpExchange,
3
+ uncertainStatuses
4
+ } from "./chunk-ICXZZNPS.js";
5
+ import {
6
+ MANAGEMENT_TIMEOUT,
7
+ lifetime,
8
+ retrying,
9
+ validTimeout
10
+ } from "./chunk-3RFP6GT5.js";
11
+ import {
12
+ knownResponse,
13
+ lifecycleReasonSchema,
14
+ limits
15
+ } from "./chunk-ID3BZXFZ.js";
16
+ import {
17
+ RequestError,
18
+ isRequestError
19
+ } from "./chunk-GLH6MEI2.js";
20
+
21
+ // src/configuration.ts
22
+ function questConfiguration(release) {
23
+ return release.configuration ?? {
24
+ defaults: Object.fromEntries(
25
+ Object.entries(release.fields).map(([key, field]) => [
26
+ key,
27
+ field.default
28
+ ])
29
+ ),
30
+ overrides: { ...release.values },
31
+ preserved: Object.keys(release.values)
32
+ };
33
+ }
34
+
35
+ // src/server/errors.ts
36
+ import * as z from "zod";
37
+ var ManagementErrorCode = {
38
+ /** The input or an option failed validation before anything was sent (kind `client`). */
39
+ InvalidInput: "invalid-input",
40
+ /** The client's `getToken` failed before anything was sent (kind `client` or `network`). */
41
+ Credential: "credential",
42
+ Network: "network",
43
+ Timeout: "timeout",
44
+ Aborted: "aborted",
45
+ InvalidResponse: "invalid-response"
46
+ };
47
+ var managementErrorSchema = /* @__PURE__ */ (() => z.looseObject({
48
+ error: z.string(),
49
+ code: z.string().optional()
50
+ }))();
51
+ function uncertainOutcome(init) {
52
+ if (init.method === void 0 || init.method === "GET") {
53
+ return false;
54
+ }
55
+ switch (init.kind) {
56
+ case "network":
57
+ case "timeout":
58
+ case "aborted":
59
+ return true;
60
+ case "http":
61
+ return uncertainStatuses.has(init.status ?? 0);
62
+ case "invalid-response":
63
+ return (init.status ?? 0) >= 200 && (init.status ?? 0) < 300;
64
+ default:
65
+ return false;
66
+ }
67
+ }
68
+ var managementErrorBrand = /* @__PURE__ */ (() => /* @__PURE__ */ Symbol.for("@domino-sdk/relay.ManagementError"))();
69
+ function isManagementError(value) {
70
+ return isRequestError(value) && value[managementErrorBrand] === true;
71
+ }
72
+ var ManagementError = class extends RequestError {
73
+ name = "ManagementError";
74
+ [managementErrorBrand] = true;
75
+ /** The rest of the server's error body besides `error` and `code`, such as `moved`; absent when there is none. */
76
+ details;
77
+ /** The request's method; absent when the call failed before forming a request. */
78
+ method;
79
+ /** The management API path, below `/management/v1`, without its query; absent like `method`. */
80
+ path;
81
+ constructor(init) {
82
+ super(init.message, {
83
+ kind: init.kind,
84
+ uncertain: init.uncertain ?? uncertainOutcome(init),
85
+ status: init.status,
86
+ code: init.code,
87
+ operationId: init.actionId,
88
+ replaySafe: init.replaySafe,
89
+ retryAfter: init.retryAfter,
90
+ cause: init.cause
91
+ });
92
+ this.details = init.details && Object.keys(init.details).length ? init.details : void 0;
93
+ this.method = init.method;
94
+ this.path = init.path;
95
+ }
96
+ };
97
+ var DEFAULT_MANAGEMENT_TIMEOUT = MANAGEMENT_TIMEOUT;
98
+
99
+ // src/server/transport.ts
100
+ import * as z2 from "zod";
101
+ var ManagementUploadBody = class {
102
+ constructor(body, headers, actionId) {
103
+ this.body = body;
104
+ this.headers = headers;
105
+ this.actionId = actionId;
106
+ }
107
+ body;
108
+ headers;
109
+ actionId;
110
+ };
111
+ function failureCause(error) {
112
+ if (typeof error !== "object" || error === null || !("cause" in error)) {
113
+ return {};
114
+ }
115
+ const { cause } = error;
116
+ return typeof cause === "object" && cause !== null ? cause : {};
117
+ }
118
+ function actionIdOf(input) {
119
+ if (input instanceof ManagementUploadBody) {
120
+ return input.actionId;
121
+ }
122
+ return typeof input === "object" && input !== null && "actionId" in input && typeof input.actionId === "string" ? input.actionId : void 0;
123
+ }
124
+ function unsent(error) {
125
+ const code = String(failureCause(error).code ?? "");
126
+ return /^(ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ENETUNREACH|EHOSTUNREACH|UND_ERR_CONNECT_TIMEOUT)$|CERT|TLS|SSL/.test(
127
+ code
128
+ );
129
+ }
130
+ function redirected(error) {
131
+ return /redirect/i.test(String(failureCause(error).message ?? ""));
132
+ }
133
+ function checkedTimeout(timeout) {
134
+ if (timeout !== void 0 && !validTimeout(timeout)) {
135
+ throw new ManagementError({
136
+ kind: "client",
137
+ code: ManagementErrorCode.InvalidInput,
138
+ message: "Management timeout must be a positive, finite number of milliseconds"
139
+ });
140
+ }
141
+ return timeout;
142
+ }
143
+ function managementTransport(options) {
144
+ const clientTimeout = checkedTimeout(options.timeout) ?? DEFAULT_MANAGEMENT_TIMEOUT;
145
+ const redirect = options.redirect ? { redirect: options.redirect } : {};
146
+ const http = createHttpExchange(
147
+ {
148
+ baseUrl: `${options.baseUrl}/management/v1`,
149
+ headers: options.headers,
150
+ getToken: options.getToken,
151
+ fetch: options.fetch,
152
+ organization: options.organization,
153
+ project: options.project,
154
+ environment: options.environment
155
+ },
156
+ {
157
+ client: options.client,
158
+ credentialLast: true,
159
+ // A redirect fetch refused to follow was answered without being applied. The participant
160
+ // client has no such rule, so there a write that failed to connect stays uncertain.
161
+ neverSent: (error) => unsent(error) || redirected(error),
162
+ abortReason: true,
163
+ messages: {
164
+ aborted: "The management request was cancelled",
165
+ timeout: (milliseconds) => `The management request did not finish within ${milliseconds} ms`,
166
+ network: () => "The management request failed before Domino answered",
167
+ credential: "Could not get a management credential",
168
+ invalidToken: "getToken returned a value that is not a token",
169
+ invalidOptions: "Management headers, organization and project must be valid HTTP header values"
170
+ // No `unsendable`: a header or body that cannot be sent rejects with the platform's error.
171
+ },
172
+ makeError: (message, error, context) => new ManagementError({ ...context, ...error, message }),
173
+ // A body that is not the server's error JSON still rejects with the status.
174
+ parseRefusal: (body) => {
175
+ const parsed = managementErrorSchema.safeParse(body);
176
+ if (!parsed.success) {
177
+ return {};
178
+ }
179
+ const { error, code, ...details } = parsed.data;
180
+ return { message: error, code, details };
181
+ }
182
+ }
183
+ );
184
+ function callLifetime(call) {
185
+ return lifetime(
186
+ checkedTimeout(call?.timeout) ?? clientTimeout,
187
+ call?.signal ?? void 0
188
+ );
189
+ }
190
+ async function raw(path, init) {
191
+ const { timeout, signal, ...fetchInit } = init ?? {};
192
+ const life = callLifetime({ timeout, signal: signal ?? void 0 });
193
+ try {
194
+ return await http.send(
195
+ path,
196
+ {
197
+ method: fetchInit.method,
198
+ headers: fetchInit.headers,
199
+ body: fetchInit.body,
200
+ init: { ...fetchInit, ...redirect }
201
+ },
202
+ {
203
+ method: (fetchInit.method ?? "GET").toUpperCase(),
204
+ path: path.split("?")[0],
205
+ replaySafe: false
206
+ },
207
+ life
208
+ );
209
+ } finally {
210
+ life.end();
211
+ }
212
+ }
213
+ async function exchange(path, schema, input, method, call, replaySafe, tolerant = false) {
214
+ const actionId = actionIdOf(input);
215
+ const context = {
216
+ method,
217
+ replaySafe,
218
+ path: path.split("?")[0],
219
+ ...actionId ? { actionId } : {}
220
+ };
221
+ const tolerance = tolerant ? { "X-Domino-Response": "tolerant-v1" } : {};
222
+ const request = input instanceof ManagementUploadBody ? {
223
+ method,
224
+ headers: {
225
+ "Content-Type": input.body.type,
226
+ ...input.headers,
227
+ ...tolerance
228
+ },
229
+ body: input.body,
230
+ init: redirect
231
+ } : { method, headers: tolerance, json: input, init: redirect };
232
+ const life = callLifetime(call);
233
+ try {
234
+ return await retrying(
235
+ life,
236
+ { replaySafe: method === "GET" || replaySafe },
237
+ async () => {
238
+ const response = await http.send(path, request, context, life);
239
+ let body;
240
+ try {
241
+ body = response.status === 204 ? null : await response.json();
242
+ } catch (error) {
243
+ if (error instanceof SyntaxError && !life.signal.aborted) {
244
+ throw new ManagementError({
245
+ ...context,
246
+ kind: "invalid-response",
247
+ code: ManagementErrorCode.InvalidResponse,
248
+ status: response.status,
249
+ message: "Domino answered with a body that is not JSON",
250
+ cause: error
251
+ });
252
+ }
253
+ throw http.interrupted(error, method, context, life, {
254
+ sent: true,
255
+ status: response.status,
256
+ headers: response.headers
257
+ });
258
+ }
259
+ const parsed = knownResponse(schema).safeParse(
260
+ tolerant ? { status: response.status, operationId: actionId, result: body } : body
261
+ );
262
+ if (!parsed.success) {
263
+ throw new ManagementError({
264
+ ...context,
265
+ kind: "invalid-response",
266
+ code: ManagementErrorCode.InvalidResponse,
267
+ status: response.status,
268
+ message: "Domino answered with a response this client does not recognize",
269
+ cause: parsed.error
270
+ });
271
+ }
272
+ return parsed.data;
273
+ }
274
+ );
275
+ } finally {
276
+ life.end();
277
+ }
278
+ }
279
+ const json = ({
280
+ path,
281
+ method,
282
+ body,
283
+ replaySafe
284
+ }) => exchange(
285
+ path,
286
+ z2.unknown(),
287
+ body,
288
+ method,
289
+ void 0,
290
+ method === "GET" || replaySafe
291
+ );
292
+ return { raw, exchange, json };
293
+ }
294
+
295
+ // src/sequence-cursor.ts
296
+ import * as z3 from "zod";
297
+ var sequenceCursorSchema = /* @__PURE__ */ (() => z3.string().regex(/^[1-9][0-9]{0,15}$/, "Invalid cursor").transform(Number).pipe(z3.number().int().positive().safe()))();
298
+
299
+ // src/referral-reward-kinds.ts
300
+ var REFERRAL_INTEGRATION_REWARD_ERROR = "Referral programs can grant points and tiered rewards; Discord roles need a quest";
301
+ var isRecord = (value) => typeof value === "object" && value !== null;
302
+ function containsReferralIntegrationReward(value) {
303
+ if (Array.isArray(value)) {
304
+ return value.some(
305
+ (reward) => isRecord(reward) && reward.kind === "integration"
306
+ );
307
+ }
308
+ if (!isRecord(value)) {
309
+ return false;
310
+ }
311
+ const definition = isRecord(value.definition) ? value.definition : value;
312
+ return isRecord(definition.rewards) && (containsReferralIntegrationReward(definition.rewards.inviter) || containsReferralIntegrationReward(definition.rewards.invitee)) || Array.isArray(definition.milestones) && definition.milestones.some(
313
+ (milestone) => isRecord(milestone) && containsReferralIntegrationReward(milestone.rewards)
314
+ );
315
+ }
316
+
317
+ // src/server/schedules.ts
318
+ import * as z4 from "zod";
319
+ import { Cron } from "croner";
320
+ var APP_SCHEDULE_LIMIT = 10;
321
+ var APP_SCHEDULE_MIN_INTERVAL = 3e5;
322
+ var APP_SCHEDULE_TIMEOUT = 3e4;
323
+ var appScheduleNameSchema = /* @__PURE__ */ (() => z4.string().regex(/^[a-z][a-z0-9-]{0,63}$/))();
324
+ var appSchedulePathSchema = /* @__PURE__ */ (() => z4.string().min(2).max(512).refine((path) => {
325
+ if (!/^\/[a-zA-Z0-9_/-]+$/.test(path) || path.startsWith("//")) {
326
+ return false;
327
+ }
328
+ return path.split("/").slice(1).every((part) => part.length > 0) && new URL(path, "https://app.invalid").pathname === path;
329
+ }, "Expected an absolute route path without a query or hidden segments"))();
330
+ function interval(value) {
331
+ const amount = Number(value.slice(0, -1));
332
+ const unit = value.slice(-1);
333
+ return amount * (unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5);
334
+ }
335
+ var everySchema = /* @__PURE__ */ (() => z4.string().regex(/^[1-9]\d{0,3}[mhd]$/).refine(
336
+ (value) => interval(value) >= limits.apps.scheduleMinIntervalMs && interval(value) <= 365 * 864e5,
337
+ "Use an interval from 5 minutes to 365 days, such as 5m, 1h or 1d"
338
+ ))();
339
+ var cronSchema = /* @__PURE__ */ (() => z4.string().max(120).refine((value) => {
340
+ const fields = value.trim().split(/\s+/);
341
+ if (fields.length !== 5 || fields.some((field) => !/^[\d*,/-]+$/.test(field))) {
342
+ return false;
343
+ }
344
+ try {
345
+ const job = new Cron(value, { paused: true, timezone: "UTC" });
346
+ if (!job.nextRun()) {
347
+ return false;
348
+ }
349
+ const minutes = new Cron(`${fields[0]} * * * *`, {
350
+ paused: true,
351
+ timezone: "UTC"
352
+ });
353
+ const times = minutes.nextRuns(13, /* @__PURE__ */ new Date("2024-01-01T00:00:00Z"));
354
+ return times.every(
355
+ (time, i) => i === 0 || time.getTime() - times[i - 1].getTime() >= limits.apps.scheduleMinIntervalMs
356
+ );
357
+ } catch {
358
+ return false;
359
+ }
360
+ }, "Expected a five-field UTC cron expression with minute slots at least five minutes apart"))();
361
+ var declaration = /* @__PURE__ */ (() => ({
362
+ name: appScheduleNameSchema,
363
+ path: appSchedulePathSchema,
364
+ description: z4.string().min(1).max(500)
365
+ }))();
366
+ var everySchedule = /* @__PURE__ */ (() => z4.object({ ...declaration, every: everySchema }))();
367
+ var cronSchedule = /* @__PURE__ */ (() => z4.object({ ...declaration, cron: cronSchema }))();
368
+ var appScheduleSchema = /* @__PURE__ */ (() => z4.union([
369
+ everySchedule.strict(),
370
+ cronSchedule.strict()
371
+ ]))();
372
+ var appSchedulesSchema = /* @__PURE__ */ (() => z4.array(appScheduleSchema).max(limits.apps.schedules).refine(
373
+ (items) => new Set(items.map((item) => item.name)).size === items.length,
374
+ "Schedule names must be unique"
375
+ ))();
376
+ function nextScheduleRun(schedule, after) {
377
+ if ("every" in schedule) {
378
+ return after + interval(schedule.every);
379
+ }
380
+ const next = new Cron(schedule.cron, {
381
+ paused: true,
382
+ timezone: "UTC"
383
+ }).nextRun(new Date(after));
384
+ if (!next) {
385
+ throw new Error("Schedule has no next occurrence");
386
+ }
387
+ return next.getTime();
388
+ }
389
+ var appScheduleStateSchema = /* @__PURE__ */ (() => z4.enum(["active", "paused", "archived"]))();
390
+ var appScheduleStateInputSchema = /* @__PURE__ */ (() => z4.object({
391
+ state: appScheduleStateSchema,
392
+ reason: lifecycleReasonSchema.optional()
393
+ }).strict())();
394
+ var APP_SCHEDULE_RESULT_BYTES = 16384;
395
+ var appScheduleDiagnosticSchema = /* @__PURE__ */ (() => z4.object({
396
+ level: z4.enum(["error", "warning", "info"]),
397
+ message: z4.string().min(1).max(500),
398
+ /** What the line is about, such as a member, record or tracker ID. */
399
+ subject: z4.string().min(1).max(200).optional(),
400
+ /** A stable code the app chooses, such as `ingest-timeout`. */
401
+ code: z4.string().min(1).max(100).optional()
402
+ }))();
403
+ var appScheduleResultSchema = /* @__PURE__ */ (() => z4.object({
404
+ outcome: z4.enum(["succeeded", "partial", "failed"]),
405
+ summary: z4.string().min(1).max(500).optional(),
406
+ /** Counts and gauges, such as processed and failed members. */
407
+ metrics: z4.record(z4.string().regex(/^[A-Za-z][\w.-]{0,63}$/), z4.number()).refine(
408
+ (metrics) => Object.keys(metrics).length <= 50,
409
+ "Report at most 50 metrics"
410
+ ).optional(),
411
+ diagnostics: z4.array(appScheduleDiagnosticSchema).max(50).optional()
412
+ }))();
413
+ function scheduleResult(result) {
414
+ const body = JSON.stringify(appScheduleResultSchema.parse(result));
415
+ if (new TextEncoder().encode(body).byteLength > limits.apps.scheduleResultBytes) {
416
+ throw new Error(
417
+ `A schedule result must be at most ${limits.apps.scheduleResultBytes.toLocaleString("en-US")} bytes of JSON: send fewer or shorter diagnostics`
418
+ );
419
+ }
420
+ return new Response(body, {
421
+ headers: { "Content-Type": "application/json" }
422
+ });
423
+ }
424
+ var appScheduleRunSchema = /* @__PURE__ */ (() => z4.object({
425
+ id: z4.string().uuid(),
426
+ build: z4.string().uuid(),
427
+ startedAt: z4.number(),
428
+ scheduledAt: z4.number(),
429
+ manual: z4.boolean(),
430
+ status: z4.enum(["queued", "running", "succeeded", "failed", "uncertain"]),
431
+ duration: z4.number().nullable(),
432
+ /** Why the run failed or is uncertain, or why Relay ignored the app's result. */
433
+ error: z4.string().nullable(),
434
+ /** The app's JSON answer when it sent a valid result. Absent on runs from before results. */
435
+ result: appScheduleResultSchema.nullable().optional()
436
+ }))();
437
+ var appScheduleRunsSchema = /* @__PURE__ */ (() => z4.object({
438
+ /** Newest first: the latest twenty runs of one schedule, including a queued or running one. */
439
+ runs: z4.array(appScheduleRunSchema)
440
+ }))();
441
+ var appScheduleListSchema = /* @__PURE__ */ (() => z4.object({
442
+ state: appScheduleStateSchema,
443
+ schedules: z4.array(
444
+ z4.object({
445
+ declaration: z4.union([everySchedule, cronSchedule]),
446
+ nextRun: z4.number().nullable(),
447
+ blocked: z4.boolean(),
448
+ lastRun: appScheduleRunSchema.nullable()
449
+ })
450
+ )
451
+ }))();
452
+ var scheduledInvocationSchema = /* @__PURE__ */ (() => z4.object({
453
+ id: z4.string().uuid(),
454
+ build: z4.string().uuid(),
455
+ name: appScheduleNameSchema,
456
+ scheduledAt: z4.number().int(),
457
+ startedAt: z4.number().int(),
458
+ manual: z4.boolean()
459
+ }).strict())();
460
+ async function verifyScheduledRequest(request, key) {
461
+ const signature = request.headers.get("X-Domino-Schedule-Signature");
462
+ const url = new URL(request.url);
463
+ if (request.method !== "POST" || url.search !== "" || url.hash !== "" || !key || !signature || !/^[a-f0-9]{64}$/.test(signature)) {
464
+ return null;
465
+ }
466
+ const reader = request.clone().body?.getReader();
467
+ if (!reader) {
468
+ return null;
469
+ }
470
+ let body = "";
471
+ let size = 0;
472
+ const decoder = new TextDecoder();
473
+ try {
474
+ for (; ; ) {
475
+ const chunk = await reader.read();
476
+ if (chunk.done) {
477
+ break;
478
+ }
479
+ size += chunk.value.byteLength;
480
+ if (size > 4096) {
481
+ void reader.cancel().catch(() => {
482
+ });
483
+ return null;
484
+ }
485
+ body += decoder.decode(chunk.value, { stream: true });
486
+ }
487
+ body += decoder.decode();
488
+ } catch {
489
+ return null;
490
+ }
491
+ const secret = await crypto.subtle.importKey(
492
+ "raw",
493
+ new TextEncoder().encode(key),
494
+ { name: "HMAC", hash: "SHA-256" },
495
+ false,
496
+ ["verify"]
497
+ );
498
+ const bytes = Uint8Array.from(
499
+ signature.match(/../g) ?? [],
500
+ (byte) => Number.parseInt(byte, 16)
501
+ );
502
+ const valid = await crypto.subtle.verify(
503
+ "HMAC",
504
+ secret,
505
+ bytes,
506
+ new TextEncoder().encode(`POST
507
+ ${url.pathname}
508
+ ${body}`)
509
+ );
510
+ if (!valid) {
511
+ return null;
512
+ }
513
+ const parsed = scheduledInvocationSchema.safeParse(
514
+ await new Response(body).json().catch(() => null)
515
+ );
516
+ if (!parsed.success || Math.abs(Date.now() - parsed.data.startedAt) > 6e4) {
517
+ return null;
518
+ }
519
+ return parsed.data;
520
+ }
521
+
522
+ export {
523
+ questConfiguration,
524
+ ManagementErrorCode,
525
+ managementErrorSchema,
526
+ isManagementError,
527
+ ManagementError,
528
+ DEFAULT_MANAGEMENT_TIMEOUT,
529
+ ManagementUploadBody,
530
+ actionIdOf,
531
+ managementTransport,
532
+ sequenceCursorSchema,
533
+ REFERRAL_INTEGRATION_REWARD_ERROR,
534
+ containsReferralIntegrationReward,
535
+ APP_SCHEDULE_LIMIT,
536
+ APP_SCHEDULE_MIN_INTERVAL,
537
+ APP_SCHEDULE_TIMEOUT,
538
+ appScheduleNameSchema,
539
+ appSchedulePathSchema,
540
+ appScheduleSchema,
541
+ appSchedulesSchema,
542
+ nextScheduleRun,
543
+ appScheduleStateSchema,
544
+ appScheduleStateInputSchema,
545
+ APP_SCHEDULE_RESULT_BYTES,
546
+ appScheduleDiagnosticSchema,
547
+ appScheduleResultSchema,
548
+ scheduleResult,
549
+ appScheduleRunSchema,
550
+ appScheduleRunsSchema,
551
+ appScheduleListSchema,
552
+ scheduledInvocationSchema,
553
+ verifyScheduledRequest
554
+ };