@domino-sdk/relay 1.1.1 → 1.3.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.
@@ -180,6 +180,28 @@ var testMemberResetResultSchema = z.object({
180
180
  member: identifier,
181
181
  deleted: z.literal(true)
182
182
  });
183
+ var testMemberHistoryQuerySchema = z.object({
184
+ /** Inclusive lower bound on credited activity time, in epoch milliseconds. */
185
+ since: z.coerce.number().int().nonnegative().safe().optional()
186
+ });
187
+ var testMemberHistorySchema = z.object({
188
+ /** Newest credited activity first, up to 500 attempts. */
189
+ attempts: z.array(
190
+ attemptSchema.extend({ eligibleAt: z.number().int().nonnegative().safe() })
191
+ ),
192
+ /** Tracker trigger outcomes that admitted no attempt, newest occurrence first, up to 500. */
193
+ skipped: z.array(
194
+ z.object({
195
+ quest: identifier,
196
+ tracker: identifier,
197
+ record: z.string(),
198
+ code: z.string().min(1),
199
+ occurredAt: z.number().int().nonnegative().safe()
200
+ })
201
+ ),
202
+ /** False when older entries were omitted from either list. */
203
+ complete: z.boolean()
204
+ });
183
205
 
184
206
  // src/server/webhooks.ts
185
207
  import { z as z2 } from "zod";
@@ -421,6 +443,11 @@ var outputPathSchema = z5.string().min(1).max(512).refine(
421
443
  );
422
444
  var appRoutingSchema = z5.enum(["legacy", "transparent"]).default("legacy");
423
445
  var APP_SECRET_LIMIT = 50;
446
+ var APP_KV_LIMIT = 5;
447
+ var APP_SQL_LIMIT = 5;
448
+ var APP_MIGRATION_LIMIT = 100;
449
+ var APP_MIGRATION_FILE_BYTES = 9e4;
450
+ var APP_MIGRATION_TOTAL_BYTES = 1e6;
424
451
  var appSecretNameSchema = z5.string().regex(
425
452
  /^[A-Z_][A-Z0-9_]{0,63}$/,
426
453
  "Use 1-64 uppercase letters, digits, and underscores, not starting with a digit"
@@ -451,6 +478,110 @@ var appSecretListSchema = z5.object({
451
478
  declared: z5.array(appSecretDeclarationSchema.extend({ name: appSecretNameSchema })).default([])
452
479
  });
453
480
  var hostedAppSecretsSchema = z5.object({ secrets: z5.record(appSecretNameSchema, appSecretValueSchema) }).strict();
481
+ var storageDescription = z5.object({
482
+ description: z5.string().trim().min(1).max(500)
483
+ }).strict();
484
+ var appStorageSchema = z5.object({
485
+ kv: z5.record(appSecretNameSchema, storageDescription).refine(
486
+ (stores) => Object.keys(stores).length <= APP_KV_LIMIT,
487
+ `Declare at most ${APP_KV_LIMIT} KV stores`
488
+ ).default({}),
489
+ sql: z5.record(
490
+ appSecretNameSchema,
491
+ storageDescription.extend({
492
+ migrations: outputPathSchema.optional()
493
+ }).strict()
494
+ ).refine(
495
+ (stores) => Object.keys(stores).length <= APP_SQL_LIMIT,
496
+ `Declare at most ${APP_SQL_LIMIT} SQL stores`
497
+ ).default({})
498
+ }).strict();
499
+ var appStorageKindSchema = z5.enum(["kv", "sql"]);
500
+ var appStorageListSchema = z5.object({
501
+ stores: z5.array(
502
+ z5.object({
503
+ kind: z5.string(),
504
+ name: appSecretNameSchema,
505
+ createdAt: z5.number().nullable(),
506
+ declared: z5.boolean(),
507
+ description: z5.string().optional()
508
+ })
509
+ )
510
+ });
511
+ var APP_STORAGE_ROW_LIMIT = 50;
512
+ var APP_STORAGE_PREVIEW_CHARACTERS = 2e3;
513
+ var appStorageCellSchema = z5.union([
514
+ z5.string(),
515
+ z5.number(),
516
+ z5.null(),
517
+ z5.object({ text: z5.string(), truncated: z5.literal(true) }),
518
+ z5.object({ blob: z5.number().int().min(0) })
519
+ ]);
520
+ var appStorageTablesSchema = z5.object({
521
+ tables: z5.array(
522
+ /** `kind` is SQLite's: `table` or `view`. */
523
+ z5.object({ name: z5.string(), kind: z5.string() })
524
+ )
525
+ });
526
+ var appStorageRowsSchema = z5.object({
527
+ table: z5.string(),
528
+ columns: z5.array(z5.string()),
529
+ rows: z5.array(z5.array(appStorageCellSchema)),
530
+ offset: z5.number().int().min(0),
531
+ total: z5.number().int().min(0)
532
+ });
533
+ var appStorageKeysSchema = z5.object({
534
+ keys: z5.array(
535
+ z5.object({ name: z5.string(), expiration: z5.number().nullable() })
536
+ ),
537
+ /** Pass back to read the next page; null on the last one. */
538
+ cursor: z5.string().nullable()
539
+ });
540
+ var appStorageValueSchema = z5.object({
541
+ key: z5.string(),
542
+ size: z5.number().int().min(0),
543
+ /** Null when the value is not UTF-8 text. */
544
+ text: z5.string().nullable(),
545
+ truncated: z5.boolean()
546
+ });
547
+ var appMigrationNameSchema = z5.string().max(255).regex(/^[\w-][\w.-]*\.sql$/);
548
+ function compareAppMigrations(a, b) {
549
+ const left = Number.parseInt(a.split("_")[0], 10);
550
+ const right = Number.parseInt(b.split("_")[0], 10);
551
+ if (left !== right) {
552
+ if (Number.isFinite(left) && Number.isFinite(right)) {
553
+ return left - right;
554
+ }
555
+ if (Number.isFinite(left)) {
556
+ return -1;
557
+ }
558
+ if (Number.isFinite(right)) {
559
+ return 1;
560
+ }
561
+ }
562
+ return a < b ? -1 : a > b ? 1 : 0;
563
+ }
564
+ var appMigrationsSchema = z5.record(
565
+ appSecretNameSchema,
566
+ z5.array(
567
+ z5.object({
568
+ name: appMigrationNameSchema,
569
+ sql: z5.string().min(1).refine(
570
+ (sql) => new TextEncoder().encode(sql).length <= APP_MIGRATION_FILE_BYTES,
571
+ `A migration file must not exceed ${APP_MIGRATION_FILE_BYTES} bytes`
572
+ )
573
+ }).strict()
574
+ ).max(APP_MIGRATION_LIMIT).refine(
575
+ (files) => new Set(files.map((file) => file.name)).size === files.length,
576
+ "Duplicate migration filenames"
577
+ )
578
+ ).refine(
579
+ (stores) => Object.values(stores).flat().reduce(
580
+ (total, file) => total + new TextEncoder().encode(file.sql).length,
581
+ 0
582
+ ) <= APP_MIGRATION_TOTAL_BYTES,
583
+ `Migrations must not exceed ${APP_MIGRATION_TOTAL_BYTES} bytes in total`
584
+ );
454
585
  var appScripts = {
455
586
  routing: appRoutingSchema,
456
587
  devScript: z5.string().regex(/^[\w:-]+$/),
@@ -469,12 +600,31 @@ var workerSettings = {
469
600
  z5.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).refine((name) => name !== "ASSETS"),
470
601
  z5.string()
471
602
  ).default({}),
472
- secrets: appSecretDeclarationsSchema.default({})
603
+ secrets: appSecretDeclarationsSchema.default({}),
604
+ storage: appStorageSchema.optional()
473
605
  };
474
- var distinctBindings = (worker) => !Object.keys(worker.secrets).some((name) => name in worker.vars);
475
- var distinctBindingsMessage = {
476
- message: "A name can't be both an app var and a declared secret",
477
- path: ["secrets"]
606
+ var distinctBindings = (worker, ctx) => {
607
+ const owners = /* @__PURE__ */ new Map();
608
+ const sources = [
609
+ ["vars", "an app var", Object.keys(worker.vars)],
610
+ ["secrets", "a declared secret", Object.keys(worker.secrets)],
611
+ ["storage", "a KV store", Object.keys(worker.storage?.kv ?? {})],
612
+ ["storage", "a SQL store", Object.keys(worker.storage?.sql ?? {})]
613
+ ];
614
+ for (const [path, owner, names] of sources) {
615
+ for (const name of names) {
616
+ const first = owners.get(name);
617
+ if (first) {
618
+ ctx.addIssue({
619
+ code: "custom",
620
+ message: `Binding name ${name} is used by both ${first} and ${owner}`,
621
+ path: [path]
622
+ });
623
+ } else {
624
+ owners.set(name, owner);
625
+ }
626
+ }
627
+ }
478
628
  };
479
629
  var hostedAppSchema = z5.discriminatedUnion("kind", [
480
630
  z5.object({
@@ -488,7 +638,7 @@ var hostedAppSchema = z5.discriminatedUnion("kind", [
488
638
  assetsDirectory: outputPathSchema.optional(),
489
639
  ...appScripts,
490
640
  ...workerSettings
491
- }).strict().refine(distinctBindings, distinctBindingsMessage)
641
+ }).strict().superRefine(distinctBindings)
492
642
  ]);
493
643
  var repositorySchema = z5.object({
494
644
  id: z5.string().uuid(),
@@ -602,6 +752,7 @@ var artifactFields = {
602
752
  routing: appRoutingSchema,
603
753
  worker: z5.object({
604
754
  ...workerSettings,
755
+ migrations: appMigrationsSchema.optional(),
605
756
  modules: z5.array(
606
757
  z5.object({
607
758
  path: outputPathSchema.refine((path) => path !== "metadata"),
@@ -614,7 +765,7 @@ var artifactFields = {
614
765
  content: base64Schema.max(14e6)
615
766
  }).strict()
616
767
  ).min(1).max(500)
617
- }).strict().refine(distinctBindings, distinctBindingsMessage).optional(),
768
+ }).strict().superRefine(distinctBindings).optional(),
618
769
  assets: z5.array(
619
770
  z5.object({
620
771
  path: assetPathSchema,
@@ -639,6 +790,14 @@ var buildArtifactsSchema = z5.discriminatedUnion("format", [
639
790
  ]).superRefine((value, ctx) => {
640
791
  if (value.worker) {
641
792
  const modules = value.worker.modules;
793
+ for (const name of Object.keys(value.worker.migrations ?? {})) {
794
+ if (!value.worker.storage?.sql[name]?.migrations) {
795
+ ctx.addIssue({
796
+ code: "custom",
797
+ message: `Migrations for undeclared SQL store ${name}`
798
+ });
799
+ }
800
+ }
642
801
  if (new Set(modules.map((m) => m.path)).size !== modules.length) {
643
802
  ctx.addIssue({
644
803
  code: "custom",
@@ -2157,6 +2316,11 @@ function createManagementClient(options) {
2157
2316
  call
2158
2317
  ),
2159
2318
  list: (call) => get("/test-members", z8.array(testMemberSchema), call),
2319
+ history: (member, query = {}, call) => get(
2320
+ `/test-members/${identifier.parse(member)}/history${queryString(testMemberHistoryQuerySchema.parse(query))}`,
2321
+ testMemberHistorySchema,
2322
+ call
2323
+ ),
2160
2324
  act: (member, input, call) => post(
2161
2325
  `/test-members/${identifier.parse(member)}/actions`,
2162
2326
  attemptSchema,
@@ -2270,6 +2434,49 @@ function createManagementClient(options) {
2270
2434
  });
2271
2435
  }
2272
2436
  },
2437
+ /**
2438
+ * The hosted app's KV and SQL stores in test. `list` needs `read`; reading their contents and
2439
+ * deleting a store need `publish`. Reads never change data, and only a store no serving build
2440
+ * declares can be deleted.
2441
+ */
2442
+ storage: {
2443
+ list: (call) => get("/storage", appStorageListSchema, call),
2444
+ /** A SQL store's tables and views, without SQLite's and D1's own. */
2445
+ tables: (name, call) => get(
2446
+ `/storage/sql/${appSecretNameSchema.parse(name)}/tables`,
2447
+ appStorageTablesSchema,
2448
+ call
2449
+ ),
2450
+ /** One page of 50 rows in the table's storage order, which rows changing in between can shift. */
2451
+ rows: (name, table, options2 = {}, call) => get(
2452
+ `/storage/sql/${appSecretNameSchema.parse(name)}/rows?${new URLSearchParams({ table, offset: String(options2.offset ?? 0) })}`,
2453
+ appStorageRowsSchema,
2454
+ call
2455
+ ),
2456
+ /** One page of a KV store's keys; pass the returned `cursor` for the next. */
2457
+ keys: (name, options2 = {}, call) => get(
2458
+ `/storage/kv/${appSecretNameSchema.parse(name)}/keys?${new URLSearchParams(
2459
+ Object.entries(options2).filter(
2460
+ (entry) => entry[1] !== void 0
2461
+ )
2462
+ )}`,
2463
+ appStorageKeysSchema,
2464
+ call
2465
+ ),
2466
+ /** A KV value's size and, when it is UTF-8 text, a preview. */
2467
+ value: (name, key, call) => get(
2468
+ `/storage/kv/${appSecretNameSchema.parse(name)}/value?${new URLSearchParams({ key })}`,
2469
+ appStorageValueSchema,
2470
+ call
2471
+ ),
2472
+ /** Deletes a store no serving build declares, with all of its data. */
2473
+ delete: async (kind, name, call) => {
2474
+ await raw(`/storage/${kind}/${appSecretNameSchema.parse(name)}`, {
2475
+ ...call,
2476
+ method: "DELETE"
2477
+ });
2478
+ }
2479
+ },
2273
2480
  /**
2274
2481
  * The chains quest code can read token balances on with `ctx.wallet.balance()`, with their
2275
2482
  * names; requires `read` permission. Any other chain fails the evaluation.
@@ -2437,7 +2644,14 @@ function createManagementClient(options) {
2437
2644
  });
2438
2645
  }
2439
2646
  export {
2647
+ APP_KV_LIMIT,
2648
+ APP_MIGRATION_FILE_BYTES,
2649
+ APP_MIGRATION_LIMIT,
2650
+ APP_MIGRATION_TOTAL_BYTES,
2440
2651
  APP_SECRET_LIMIT,
2652
+ APP_SQL_LIMIT,
2653
+ APP_STORAGE_PREVIEW_CHARACTERS,
2654
+ APP_STORAGE_ROW_LIMIT,
2441
2655
  DEFAULT_MANAGEMENT_TIMEOUT,
2442
2656
  ManagementError,
2443
2657
  ManagementErrorCode,
@@ -2449,6 +2663,7 @@ export {
2449
2663
  accountProfileSchema,
2450
2664
  activityTypeSchema,
2451
2665
  activityTypes,
2666
+ appMigrationNameSchema,
2452
2667
  appRoutingSchema,
2453
2668
  appSecretDeclarationSchema,
2454
2669
  appSecretDeclarationsSchema,
@@ -2457,6 +2672,14 @@ export {
2457
2672
  appSecretNameSchema,
2458
2673
  appSecretSchema,
2459
2674
  appSecretValueSchema,
2675
+ appStorageCellSchema,
2676
+ appStorageKeysSchema,
2677
+ appStorageKindSchema,
2678
+ appStorageListSchema,
2679
+ appStorageRowsSchema,
2680
+ appStorageSchema,
2681
+ appStorageTablesSchema,
2682
+ appStorageValueSchema,
2460
2683
  assetPathSchema,
2461
2684
  auditRecordSchema,
2462
2685
  balanceCheckSchema,
@@ -2466,6 +2689,7 @@ export {
2466
2689
  buildSnapshotSchema,
2467
2690
  buildStatusSchema,
2468
2691
  commitSchema,
2692
+ compareAppMigrations,
2469
2693
  completionRevocationSchema,
2470
2694
  completionRevokeSchema,
2471
2695
  createManagementClient,
@@ -2549,6 +2773,8 @@ export {
2549
2773
  teamSchema,
2550
2774
  testMemberActionSchema,
2551
2775
  testMemberCreateSchema,
2776
+ testMemberHistoryQuerySchema,
2777
+ testMemberHistorySchema,
2552
2778
  testMemberResetResultSchema,
2553
2779
  testMemberResetSchema,
2554
2780
  testMemberSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domino-sdk/relay",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {