@domino-sdk/relay 1.1.1 → 1.2.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.
@@ -421,6 +421,11 @@ var outputPathSchema = z5.string().min(1).max(512).refine(
421
421
  );
422
422
  var appRoutingSchema = z5.enum(["legacy", "transparent"]).default("legacy");
423
423
  var APP_SECRET_LIMIT = 50;
424
+ var APP_KV_LIMIT = 5;
425
+ var APP_SQL_LIMIT = 5;
426
+ var APP_MIGRATION_LIMIT = 100;
427
+ var APP_MIGRATION_FILE_BYTES = 9e4;
428
+ var APP_MIGRATION_TOTAL_BYTES = 1e6;
424
429
  var appSecretNameSchema = z5.string().regex(
425
430
  /^[A-Z_][A-Z0-9_]{0,63}$/,
426
431
  "Use 1-64 uppercase letters, digits, and underscores, not starting with a digit"
@@ -451,6 +456,110 @@ var appSecretListSchema = z5.object({
451
456
  declared: z5.array(appSecretDeclarationSchema.extend({ name: appSecretNameSchema })).default([])
452
457
  });
453
458
  var hostedAppSecretsSchema = z5.object({ secrets: z5.record(appSecretNameSchema, appSecretValueSchema) }).strict();
459
+ var storageDescription = z5.object({
460
+ description: z5.string().trim().min(1).max(500)
461
+ }).strict();
462
+ var appStorageSchema = z5.object({
463
+ kv: z5.record(appSecretNameSchema, storageDescription).refine(
464
+ (stores) => Object.keys(stores).length <= APP_KV_LIMIT,
465
+ `Declare at most ${APP_KV_LIMIT} KV stores`
466
+ ).default({}),
467
+ sql: z5.record(
468
+ appSecretNameSchema,
469
+ storageDescription.extend({
470
+ migrations: outputPathSchema.optional()
471
+ }).strict()
472
+ ).refine(
473
+ (stores) => Object.keys(stores).length <= APP_SQL_LIMIT,
474
+ `Declare at most ${APP_SQL_LIMIT} SQL stores`
475
+ ).default({})
476
+ }).strict();
477
+ var appStorageKindSchema = z5.enum(["kv", "sql"]);
478
+ var appStorageListSchema = z5.object({
479
+ stores: z5.array(
480
+ z5.object({
481
+ kind: z5.string(),
482
+ name: appSecretNameSchema,
483
+ createdAt: z5.number().nullable(),
484
+ declared: z5.boolean(),
485
+ description: z5.string().optional()
486
+ })
487
+ )
488
+ });
489
+ var APP_STORAGE_ROW_LIMIT = 50;
490
+ var APP_STORAGE_PREVIEW_CHARACTERS = 2e3;
491
+ var appStorageCellSchema = z5.union([
492
+ z5.string(),
493
+ z5.number(),
494
+ z5.null(),
495
+ z5.object({ text: z5.string(), truncated: z5.literal(true) }),
496
+ z5.object({ blob: z5.number().int().min(0) })
497
+ ]);
498
+ var appStorageTablesSchema = z5.object({
499
+ tables: z5.array(
500
+ /** `kind` is SQLite's: `table` or `view`. */
501
+ z5.object({ name: z5.string(), kind: z5.string() })
502
+ )
503
+ });
504
+ var appStorageRowsSchema = z5.object({
505
+ table: z5.string(),
506
+ columns: z5.array(z5.string()),
507
+ rows: z5.array(z5.array(appStorageCellSchema)),
508
+ offset: z5.number().int().min(0),
509
+ total: z5.number().int().min(0)
510
+ });
511
+ var appStorageKeysSchema = z5.object({
512
+ keys: z5.array(
513
+ z5.object({ name: z5.string(), expiration: z5.number().nullable() })
514
+ ),
515
+ /** Pass back to read the next page; null on the last one. */
516
+ cursor: z5.string().nullable()
517
+ });
518
+ var appStorageValueSchema = z5.object({
519
+ key: z5.string(),
520
+ size: z5.number().int().min(0),
521
+ /** Null when the value is not UTF-8 text. */
522
+ text: z5.string().nullable(),
523
+ truncated: z5.boolean()
524
+ });
525
+ var appMigrationNameSchema = z5.string().max(255).regex(/^[\w-][\w.-]*\.sql$/);
526
+ function compareAppMigrations(a, b) {
527
+ const left = Number.parseInt(a.split("_")[0], 10);
528
+ const right = Number.parseInt(b.split("_")[0], 10);
529
+ if (left !== right) {
530
+ if (Number.isFinite(left) && Number.isFinite(right)) {
531
+ return left - right;
532
+ }
533
+ if (Number.isFinite(left)) {
534
+ return -1;
535
+ }
536
+ if (Number.isFinite(right)) {
537
+ return 1;
538
+ }
539
+ }
540
+ return a < b ? -1 : a > b ? 1 : 0;
541
+ }
542
+ var appMigrationsSchema = z5.record(
543
+ appSecretNameSchema,
544
+ z5.array(
545
+ z5.object({
546
+ name: appMigrationNameSchema,
547
+ sql: z5.string().min(1).refine(
548
+ (sql) => new TextEncoder().encode(sql).length <= APP_MIGRATION_FILE_BYTES,
549
+ `A migration file must not exceed ${APP_MIGRATION_FILE_BYTES} bytes`
550
+ )
551
+ }).strict()
552
+ ).max(APP_MIGRATION_LIMIT).refine(
553
+ (files) => new Set(files.map((file) => file.name)).size === files.length,
554
+ "Duplicate migration filenames"
555
+ )
556
+ ).refine(
557
+ (stores) => Object.values(stores).flat().reduce(
558
+ (total, file) => total + new TextEncoder().encode(file.sql).length,
559
+ 0
560
+ ) <= APP_MIGRATION_TOTAL_BYTES,
561
+ `Migrations must not exceed ${APP_MIGRATION_TOTAL_BYTES} bytes in total`
562
+ );
454
563
  var appScripts = {
455
564
  routing: appRoutingSchema,
456
565
  devScript: z5.string().regex(/^[\w:-]+$/),
@@ -469,12 +578,31 @@ var workerSettings = {
469
578
  z5.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).refine((name) => name !== "ASSETS"),
470
579
  z5.string()
471
580
  ).default({}),
472
- secrets: appSecretDeclarationsSchema.default({})
581
+ secrets: appSecretDeclarationsSchema.default({}),
582
+ storage: appStorageSchema.optional()
473
583
  };
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"]
584
+ var distinctBindings = (worker, ctx) => {
585
+ const owners = /* @__PURE__ */ new Map();
586
+ const sources = [
587
+ ["vars", "an app var", Object.keys(worker.vars)],
588
+ ["secrets", "a declared secret", Object.keys(worker.secrets)],
589
+ ["storage", "a KV store", Object.keys(worker.storage?.kv ?? {})],
590
+ ["storage", "a SQL store", Object.keys(worker.storage?.sql ?? {})]
591
+ ];
592
+ for (const [path, owner, names] of sources) {
593
+ for (const name of names) {
594
+ const first = owners.get(name);
595
+ if (first) {
596
+ ctx.addIssue({
597
+ code: "custom",
598
+ message: `Binding name ${name} is used by both ${first} and ${owner}`,
599
+ path: [path]
600
+ });
601
+ } else {
602
+ owners.set(name, owner);
603
+ }
604
+ }
605
+ }
478
606
  };
479
607
  var hostedAppSchema = z5.discriminatedUnion("kind", [
480
608
  z5.object({
@@ -488,7 +616,7 @@ var hostedAppSchema = z5.discriminatedUnion("kind", [
488
616
  assetsDirectory: outputPathSchema.optional(),
489
617
  ...appScripts,
490
618
  ...workerSettings
491
- }).strict().refine(distinctBindings, distinctBindingsMessage)
619
+ }).strict().superRefine(distinctBindings)
492
620
  ]);
493
621
  var repositorySchema = z5.object({
494
622
  id: z5.string().uuid(),
@@ -602,6 +730,7 @@ var artifactFields = {
602
730
  routing: appRoutingSchema,
603
731
  worker: z5.object({
604
732
  ...workerSettings,
733
+ migrations: appMigrationsSchema.optional(),
605
734
  modules: z5.array(
606
735
  z5.object({
607
736
  path: outputPathSchema.refine((path) => path !== "metadata"),
@@ -614,7 +743,7 @@ var artifactFields = {
614
743
  content: base64Schema.max(14e6)
615
744
  }).strict()
616
745
  ).min(1).max(500)
617
- }).strict().refine(distinctBindings, distinctBindingsMessage).optional(),
746
+ }).strict().superRefine(distinctBindings).optional(),
618
747
  assets: z5.array(
619
748
  z5.object({
620
749
  path: assetPathSchema,
@@ -639,6 +768,14 @@ var buildArtifactsSchema = z5.discriminatedUnion("format", [
639
768
  ]).superRefine((value, ctx) => {
640
769
  if (value.worker) {
641
770
  const modules = value.worker.modules;
771
+ for (const name of Object.keys(value.worker.migrations ?? {})) {
772
+ if (!value.worker.storage?.sql[name]?.migrations) {
773
+ ctx.addIssue({
774
+ code: "custom",
775
+ message: `Migrations for undeclared SQL store ${name}`
776
+ });
777
+ }
778
+ }
642
779
  if (new Set(modules.map((m) => m.path)).size !== modules.length) {
643
780
  ctx.addIssue({
644
781
  code: "custom",
@@ -2270,6 +2407,49 @@ function createManagementClient(options) {
2270
2407
  });
2271
2408
  }
2272
2409
  },
2410
+ /**
2411
+ * The hosted app's KV and SQL stores in test. `list` needs `read`; reading their contents and
2412
+ * deleting a store need `publish`. Reads never change data, and only a store no serving build
2413
+ * declares can be deleted.
2414
+ */
2415
+ storage: {
2416
+ list: (call) => get("/storage", appStorageListSchema, call),
2417
+ /** A SQL store's tables and views, without SQLite's and D1's own. */
2418
+ tables: (name, call) => get(
2419
+ `/storage/sql/${appSecretNameSchema.parse(name)}/tables`,
2420
+ appStorageTablesSchema,
2421
+ call
2422
+ ),
2423
+ /** One page of 50 rows in the table's storage order, which rows changing in between can shift. */
2424
+ rows: (name, table, options2 = {}, call) => get(
2425
+ `/storage/sql/${appSecretNameSchema.parse(name)}/rows?${new URLSearchParams({ table, offset: String(options2.offset ?? 0) })}`,
2426
+ appStorageRowsSchema,
2427
+ call
2428
+ ),
2429
+ /** One page of a KV store's keys; pass the returned `cursor` for the next. */
2430
+ keys: (name, options2 = {}, call) => get(
2431
+ `/storage/kv/${appSecretNameSchema.parse(name)}/keys?${new URLSearchParams(
2432
+ Object.entries(options2).filter(
2433
+ (entry) => entry[1] !== void 0
2434
+ )
2435
+ )}`,
2436
+ appStorageKeysSchema,
2437
+ call
2438
+ ),
2439
+ /** A KV value's size and, when it is UTF-8 text, a preview. */
2440
+ value: (name, key, call) => get(
2441
+ `/storage/kv/${appSecretNameSchema.parse(name)}/value?${new URLSearchParams({ key })}`,
2442
+ appStorageValueSchema,
2443
+ call
2444
+ ),
2445
+ /** Deletes a store no serving build declares, with all of its data. */
2446
+ delete: async (kind, name, call) => {
2447
+ await raw(`/storage/${kind}/${appSecretNameSchema.parse(name)}`, {
2448
+ ...call,
2449
+ method: "DELETE"
2450
+ });
2451
+ }
2452
+ },
2273
2453
  /**
2274
2454
  * The chains quest code can read token balances on with `ctx.wallet.balance()`, with their
2275
2455
  * names; requires `read` permission. Any other chain fails the evaluation.
@@ -2437,7 +2617,14 @@ function createManagementClient(options) {
2437
2617
  });
2438
2618
  }
2439
2619
  export {
2620
+ APP_KV_LIMIT,
2621
+ APP_MIGRATION_FILE_BYTES,
2622
+ APP_MIGRATION_LIMIT,
2623
+ APP_MIGRATION_TOTAL_BYTES,
2440
2624
  APP_SECRET_LIMIT,
2625
+ APP_SQL_LIMIT,
2626
+ APP_STORAGE_PREVIEW_CHARACTERS,
2627
+ APP_STORAGE_ROW_LIMIT,
2441
2628
  DEFAULT_MANAGEMENT_TIMEOUT,
2442
2629
  ManagementError,
2443
2630
  ManagementErrorCode,
@@ -2449,6 +2636,7 @@ export {
2449
2636
  accountProfileSchema,
2450
2637
  activityTypeSchema,
2451
2638
  activityTypes,
2639
+ appMigrationNameSchema,
2452
2640
  appRoutingSchema,
2453
2641
  appSecretDeclarationSchema,
2454
2642
  appSecretDeclarationsSchema,
@@ -2457,6 +2645,14 @@ export {
2457
2645
  appSecretNameSchema,
2458
2646
  appSecretSchema,
2459
2647
  appSecretValueSchema,
2648
+ appStorageCellSchema,
2649
+ appStorageKeysSchema,
2650
+ appStorageKindSchema,
2651
+ appStorageListSchema,
2652
+ appStorageRowsSchema,
2653
+ appStorageSchema,
2654
+ appStorageTablesSchema,
2655
+ appStorageValueSchema,
2460
2656
  assetPathSchema,
2461
2657
  auditRecordSchema,
2462
2658
  balanceCheckSchema,
@@ -2466,6 +2662,7 @@ export {
2466
2662
  buildSnapshotSchema,
2467
2663
  buildStatusSchema,
2468
2664
  commitSchema,
2665
+ compareAppMigrations,
2469
2666
  completionRevocationSchema,
2470
2667
  completionRevokeSchema,
2471
2668
  createManagementClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domino-sdk/relay",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {