@sanity/workbench-cli 1.4.0 → 1.6.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 (41) hide show
  1. package/dist/_exports/build.d.ts +46 -1
  2. package/dist/_exports/build.js +1 -0
  3. package/dist/_exports/build.js.map +1 -1
  4. package/dist/_exports/deploy.d.ts +49 -6
  5. package/dist/_exports/dev.d.ts +52 -9
  6. package/dist/_exports/index.d.ts +8 -1
  7. package/dist/_exports/preview.d.ts +169 -0
  8. package/dist/_exports/preview.js +3 -0
  9. package/dist/_exports/preview.js.map +1 -0
  10. package/dist/_exports/undeploy.d.ts +13 -1
  11. package/dist/actions/build/vite/optimize-deps.js +84 -0
  12. package/dist/actions/build/vite/optimize-deps.js.map +1 -0
  13. package/dist/actions/deploy/buildExposes.js +23 -10
  14. package/dist/actions/deploy/buildExposes.js.map +1 -1
  15. package/dist/actions/deploy/checkBuiltOutput.js +16 -2
  16. package/dist/actions/deploy/checkBuiltOutput.js.map +1 -1
  17. package/dist/actions/deploy/deployWorkbenchApp.js +19 -4
  18. package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -1
  19. package/dist/actions/dev/deriveInterfaces.js +41 -25
  20. package/dist/actions/dev/deriveInterfaces.js.map +1 -1
  21. package/dist/actions/dev/registry.js +99 -19
  22. package/dist/actions/dev/registry.js.map +1 -1
  23. package/dist/actions/dev/startWorkbenchDev.js +6 -41
  24. package/dist/actions/dev/startWorkbenchDev.js.map +1 -1
  25. package/dist/actions/dev/startWorkbenchDevServer.js +7 -3
  26. package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
  27. package/dist/actions/preview/serveBuiltApplication.js +53 -0
  28. package/dist/actions/preview/serveBuiltApplication.js.map +1 -0
  29. package/dist/actions/preview/startWorkbenchPreview.js +91 -0
  30. package/dist/actions/preview/startWorkbenchPreview.js.map +1 -0
  31. package/dist/contract.js +32 -0
  32. package/dist/contract.js.map +1 -1
  33. package/dist/defineApp.js +13 -6
  34. package/dist/defineApp.js.map +1 -1
  35. package/dist/resolveWorkbenchApp.js +3 -1
  36. package/dist/resolveWorkbenchApp.js.map +1 -1
  37. package/dist/services/applications.js +15 -1
  38. package/dist/services/applications.js.map +1 -1
  39. package/dist/util/serverOrchestration.js +75 -0
  40. package/dist/util/serverOrchestration.js.map +1 -0
  41. package/package.json +16 -12
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\n// Shared module-federation extension contract: interface (view/service) and\n// config declaration schemas, plus the versions the build stamps.\n// `zod/mini` keeps the bundle small.\n\n/** @internal */\nexport const VIEW_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const SERVICE_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION = 1\n\n/**\n * A view component. The return is opaque so the runtime helpers carry no React\n * dependency — the generated artifact renders it with the app's own React.\n * @public\n */\nexport type ViewComponent<TProps> = (props: TProps) => unknown\n\n/** @public */\nexport interface ViewComponentBaseProps<TView> {\n view: TView\n}\n\n/**\n * Component slots each interface type exposes, in render order. Source of truth\n * for {@link InterfaceType} and the build; add a type by registering it here.\n * @internal\n */\nexport const VIEW_COMPONENTS = {\n panel: ['title', 'panel'],\n} as const satisfies Record<string, readonly string[]>\n\n/** @public */\nexport type InterfaceType = keyof typeof VIEW_COMPONENTS\n\n/** @public */\nexport type ServiceType = 'worker'\n\n// Shared `name` + `src`; `kind` only tailors the validation message.\nfunction extensionDeclarationFields(kind: 'Field' | 'Service' | 'View') {\n const pattern = /^[a-zA-Z0-9_-]+$/\n return {\n name: z.string().check(z.regex(pattern, `${kind} \\`name\\` must match ${pattern}`)),\n src: z.string(),\n }\n}\n\n// Every interface (view, service) shares `name` + `src` + an optional display\n// `title` that defaults to `name` on deploy.\nfunction interfaceDeclarationFields(kind: 'Service' | 'View') {\n return {...extensionDeclarationFields(kind), title: z.optional(z.string())}\n}\n\nconst PanelViewSchema = z.object({\n type: z.literal('panel'),\n ...interfaceDeclarationFields('View'),\n})\n\n/** @internal */\nexport const InterfaceDeclarationSchema = z.discriminatedUnion('type', [PanelViewSchema])\n\nconst WorkerServiceSchema = z.object({\n type: z.literal('worker'),\n ...interfaceDeclarationFields('Service'),\n})\n\n/** @internal */\nexport const ServiceDeclarationSchema = z.discriminatedUnion('type', [WorkerServiceSchema])\n\nconst MediaLibraryFieldSchema = z.object({\n ...extensionDeclarationFields('Field'),\n public: z.optional(z.boolean()),\n title: z.string(),\n})\n\n/**\n * Stamped where the config crosses a boundary so the authoring model doesn't carry a constant discriminator.\n * @internal\n */\nexport const INSTALLATION_CONFIG_TYPE = 'installation_config'\n\n// `appType` is stamped by `unstable_defineMediaLibrary`, never authored.\nconst MediaLibraryConfigSchema = z.object({\n appType: z.literal('media-library'),\n fields: z\n .array(MediaLibraryFieldSchema)\n .check(\n z.refine(\n (fields) => new Set(fields.map((field) => field.name)).size === fields.length,\n 'Field `name` must be unique within a media library',\n ),\n ),\n})\n\n/**\n * An app's optional config, keyed by `appType`; deploys as a versioned snapshot, not an interface.\n * @internal\n */\nexport const ConfigSchema = z.discriminatedUnion('appType', [MediaLibraryConfigSchema])\n"],"names":["z","VIEW_CONTRACT_VERSION","SERVICE_CONTRACT_VERSION","MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION","VIEW_COMPONENTS","panel","extensionDeclarationFields","kind","pattern","name","string","check","regex","src","interfaceDeclarationFields","title","optional","PanelViewSchema","object","type","literal","InterfaceDeclarationSchema","discriminatedUnion","WorkerServiceSchema","ServiceDeclarationSchema","MediaLibraryFieldSchema","public","boolean","INSTALLATION_CONFIG_TYPE","MediaLibraryConfigSchema","appType","fields","array","refine","Set","map","field","size","length","ConfigSchema"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,4EAA4E;AAC5E,kEAAkE;AAClE,qCAAqC;AAErC,cAAc,GACd,OAAO,MAAMC,wBAAwB,EAAC;AAEtC,cAAc,GACd,OAAO,MAAMC,2BAA2B,EAAC;AAEzC,cAAc,GACd,OAAO,MAAMC,wCAAwC,EAAC;AActD;;;;CAIC,GACD,OAAO,MAAMC,kBAAkB;IAC7BC,OAAO;QAAC;QAAS;KAAQ;AAC3B,EAAsD;AAQtD,qEAAqE;AACrE,SAASC,2BAA2BC,IAAkC;IACpE,MAAMC,UAAU;IAChB,OAAO;QACLC,MAAMT,EAAEU,MAAM,GAAGC,KAAK,CAACX,EAAEY,KAAK,CAACJ,SAAS,GAAGD,KAAK,qBAAqB,EAAEC,SAAS;QAChFK,KAAKb,EAAEU,MAAM;IACf;AACF;AAEA,8EAA8E;AAC9E,6CAA6C;AAC7C,SAASI,2BAA2BP,IAAwB;IAC1D,OAAO;QAAC,GAAGD,2BAA2BC,KAAK;QAAEQ,OAAOf,EAAEgB,QAAQ,CAAChB,EAAEU,MAAM;IAAG;AAC5E;AAEA,MAAMO,kBAAkBjB,EAAEkB,MAAM,CAAC;IAC/BC,MAAMnB,EAAEoB,OAAO,CAAC;IAChB,GAAGN,2BAA2B,OAAO;AACvC;AAEA,cAAc,GACd,OAAO,MAAMO,6BAA6BrB,EAAEsB,kBAAkB,CAAC,QAAQ;IAACL;CAAgB,EAAC;AAEzF,MAAMM,sBAAsBvB,EAAEkB,MAAM,CAAC;IACnCC,MAAMnB,EAAEoB,OAAO,CAAC;IAChB,GAAGN,2BAA2B,UAAU;AAC1C;AAEA,cAAc,GACd,OAAO,MAAMU,2BAA2BxB,EAAEsB,kBAAkB,CAAC,QAAQ;IAACC;CAAoB,EAAC;AAE3F,MAAME,0BAA0BzB,EAAEkB,MAAM,CAAC;IACvC,GAAGZ,2BAA2B,QAAQ;IACtCoB,QAAQ1B,EAAEgB,QAAQ,CAAChB,EAAE2B,OAAO;IAC5BZ,OAAOf,EAAEU,MAAM;AACjB;AAEA;;;CAGC,GACD,OAAO,MAAMkB,2BAA2B,sBAAqB;AAE7D,yEAAyE;AACzE,MAAMC,2BAA2B7B,EAAEkB,MAAM,CAAC;IACxCY,SAAS9B,EAAEoB,OAAO,CAAC;IACnBW,QAAQ/B,EACLgC,KAAK,CAACP,yBACNd,KAAK,CACJX,EAAEiC,MAAM,CACN,CAACF,SAAW,IAAIG,IAAIH,OAAOI,GAAG,CAAC,CAACC,QAAUA,MAAM3B,IAAI,GAAG4B,IAAI,KAAKN,OAAOO,MAAM,EAC7E;AAGR;AAEA;;;CAGC,GACD,OAAO,MAAMC,eAAevC,EAAEsB,kBAAkB,CAAC,WAAW;IAACO;CAAyB,EAAC"}
1
+ {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\n// Shared module-federation extension contract: interface (view/service) and\n// config declaration schemas, plus the versions the build stamps.\n// `zod/mini` keeps the bundle small.\n\n/** @internal */\nexport const VIEW_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const SERVICE_CONTRACT_VERSION = 1\n\n/** @internal */\nexport const MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION = 1\n\n/**\n * A view component. The return is opaque so the runtime helpers carry no React\n * dependency — the generated artifact renders it with the app's own React.\n * @public\n */\nexport type ViewComponent<TProps> = (props: TProps) => unknown\n\n/** @public */\nexport interface ViewComponentBaseProps<TView> {\n view: TView\n}\n\n/**\n * Component slots each interface type exposes, in render order. Source of truth\n * for {@link InterfaceType} and the build; add a type by registering it here.\n * @internal\n */\nexport const VIEW_COMPONENTS = {\n panel: ['title', 'panel'],\n} as const satisfies Record<string, readonly string[]>\n\n/** @public */\nexport type InterfaceType = keyof typeof VIEW_COMPONENTS\n\n/** @public */\nexport type ServiceType = 'worker'\n\n/**\n * The `app` interface's dock-placement metadata. Interface metadata is\n * discriminated on `type`; `app` is the only type with a shape so far.\n * @internal\n */\nexport const AppInterfaceMetadataSchema = z.object({\n group: z.optional(z.string()),\n priority: z.optional(z.number()),\n})\n\n/** @internal */\nexport type AppInterfaceMetadata = z.infer<typeof AppInterfaceMetadataSchema>\n\n/**\n * The module-federation id a build exposes an interface at. Dev stamps the same\n * id a deploy would, so the workbench loads a local interface like a deployed one.\n * @internal\n */\nexport function interfaceModuleId(type: string, name: string): string {\n switch (type) {\n case 'app': {\n return 'App'\n }\n case 'panel': {\n return `views/${name}`\n }\n case 'worker': {\n return `services/${name}`\n }\n default: {\n throw new Error(`Cannot derive a moduleId for unknown interface type: ${type}`)\n }\n }\n}\n\n// Shared `name` + `src`; `kind` only tailors the validation message.\nfunction extensionDeclarationFields(kind: 'Field' | 'Service' | 'View') {\n const pattern = /^[a-zA-Z0-9_-]+$/\n return {\n name: z.string().check(z.regex(pattern, `${kind} \\`name\\` must match ${pattern}`)),\n src: z.string(),\n }\n}\n\n// Every interface (view, service) shares `name` + `src` + an optional display\n// `title` that defaults to `name` on deploy.\nfunction interfaceDeclarationFields(kind: 'Service' | 'View') {\n return {...extensionDeclarationFields(kind), title: z.optional(z.string())}\n}\n\nconst PanelViewSchema = z.object({\n type: z.literal('panel'),\n ...interfaceDeclarationFields('View'),\n})\n\n/** @internal */\nexport const InterfaceDeclarationSchema = z.discriminatedUnion('type', [PanelViewSchema])\n\nconst WorkerServiceSchema = z.object({\n type: z.literal('worker'),\n ...interfaceDeclarationFields('Service'),\n})\n\n/** @internal */\nexport const ServiceDeclarationSchema = z.discriminatedUnion('type', [WorkerServiceSchema])\n\nconst MediaLibraryFieldSchema = z.object({\n ...extensionDeclarationFields('Field'),\n public: z.optional(z.boolean()),\n title: z.string(),\n})\n\n/**\n * Stamped where the config crosses a boundary so the authoring model doesn't carry a constant discriminator.\n * @internal\n */\nexport const INSTALLATION_CONFIG_TYPE = 'installation_config'\n\n// `appType` is stamped by `unstable_defineMediaLibrary`, never authored.\nconst MediaLibraryConfigSchema = z.object({\n appType: z.literal('media-library'),\n fields: z\n .array(MediaLibraryFieldSchema)\n .check(\n z.refine(\n (fields) => new Set(fields.map((field) => field.name)).size === fields.length,\n 'Field `name` must be unique within a media library',\n ),\n ),\n})\n\n/**\n * An app's optional config, keyed by `appType`; deploys as a versioned snapshot, not an interface.\n * @internal\n */\nexport const ConfigSchema = z.discriminatedUnion('appType', [MediaLibraryConfigSchema])\n"],"names":["z","VIEW_CONTRACT_VERSION","SERVICE_CONTRACT_VERSION","MEDIA_LIBRARY_CONFIG_CONTRACT_VERSION","VIEW_COMPONENTS","panel","AppInterfaceMetadataSchema","object","group","optional","string","priority","number","interfaceModuleId","type","name","Error","extensionDeclarationFields","kind","pattern","check","regex","src","interfaceDeclarationFields","title","PanelViewSchema","literal","InterfaceDeclarationSchema","discriminatedUnion","WorkerServiceSchema","ServiceDeclarationSchema","MediaLibraryFieldSchema","public","boolean","INSTALLATION_CONFIG_TYPE","MediaLibraryConfigSchema","appType","fields","array","refine","Set","map","field","size","length","ConfigSchema"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,4EAA4E;AAC5E,kEAAkE;AAClE,qCAAqC;AAErC,cAAc,GACd,OAAO,MAAMC,wBAAwB,EAAC;AAEtC,cAAc,GACd,OAAO,MAAMC,2BAA2B,EAAC;AAEzC,cAAc,GACd,OAAO,MAAMC,wCAAwC,EAAC;AActD;;;;CAIC,GACD,OAAO,MAAMC,kBAAkB;IAC7BC,OAAO;QAAC;QAAS;KAAQ;AAC3B,EAAsD;AAQtD;;;;CAIC,GACD,OAAO,MAAMC,6BAA6BN,EAAEO,MAAM,CAAC;IACjDC,OAAOR,EAAES,QAAQ,CAACT,EAAEU,MAAM;IAC1BC,UAAUX,EAAES,QAAQ,CAACT,EAAEY,MAAM;AAC/B,GAAE;AAKF;;;;CAIC,GACD,OAAO,SAASC,kBAAkBC,IAAY,EAAEC,IAAY;IAC1D,OAAQD;QACN,KAAK;YAAO;gBACV,OAAO;YACT;QACA,KAAK;YAAS;gBACZ,OAAO,CAAC,MAAM,EAAEC,MAAM;YACxB;QACA,KAAK;YAAU;gBACb,OAAO,CAAC,SAAS,EAAEA,MAAM;YAC3B;QACA;YAAS;gBACP,MAAM,IAAIC,MAAM,CAAC,qDAAqD,EAAEF,MAAM;YAChF;IACF;AACF;AAEA,qEAAqE;AACrE,SAASG,2BAA2BC,IAAkC;IACpE,MAAMC,UAAU;IAChB,OAAO;QACLJ,MAAMf,EAAEU,MAAM,GAAGU,KAAK,CAACpB,EAAEqB,KAAK,CAACF,SAAS,GAAGD,KAAK,qBAAqB,EAAEC,SAAS;QAChFG,KAAKtB,EAAEU,MAAM;IACf;AACF;AAEA,8EAA8E;AAC9E,6CAA6C;AAC7C,SAASa,2BAA2BL,IAAwB;IAC1D,OAAO;QAAC,GAAGD,2BAA2BC,KAAK;QAAEM,OAAOxB,EAAES,QAAQ,CAACT,EAAEU,MAAM;IAAG;AAC5E;AAEA,MAAMe,kBAAkBzB,EAAEO,MAAM,CAAC;IAC/BO,MAAMd,EAAE0B,OAAO,CAAC;IAChB,GAAGH,2BAA2B,OAAO;AACvC;AAEA,cAAc,GACd,OAAO,MAAMI,6BAA6B3B,EAAE4B,kBAAkB,CAAC,QAAQ;IAACH;CAAgB,EAAC;AAEzF,MAAMI,sBAAsB7B,EAAEO,MAAM,CAAC;IACnCO,MAAMd,EAAE0B,OAAO,CAAC;IAChB,GAAGH,2BAA2B,UAAU;AAC1C;AAEA,cAAc,GACd,OAAO,MAAMO,2BAA2B9B,EAAE4B,kBAAkB,CAAC,QAAQ;IAACC;CAAoB,EAAC;AAE3F,MAAME,0BAA0B/B,EAAEO,MAAM,CAAC;IACvC,GAAGU,2BAA2B,QAAQ;IACtCe,QAAQhC,EAAES,QAAQ,CAACT,EAAEiC,OAAO;IAC5BT,OAAOxB,EAAEU,MAAM;AACjB;AAEA;;;CAGC,GACD,OAAO,MAAMwB,2BAA2B,sBAAqB;AAE7D,yEAAyE;AACzE,MAAMC,2BAA2BnC,EAAEO,MAAM,CAAC;IACxC6B,SAASpC,EAAE0B,OAAO,CAAC;IACnBW,QAAQrC,EACLsC,KAAK,CAACP,yBACNX,KAAK,CACJpB,EAAEuC,MAAM,CACN,CAACF,SAAW,IAAIG,IAAIH,OAAOI,GAAG,CAAC,CAACC,QAAUA,MAAM3B,IAAI,GAAG4B,IAAI,KAAKN,OAAOO,MAAM,EAC7E;AAGR;AAEA;;;CAGC,GACD,OAAO,MAAMC,eAAe7C,EAAE4B,kBAAkB,CAAC,WAAW;IAACO;CAAyB,EAAC"}
package/dist/defineApp.js CHANGED
@@ -1,6 +1,15 @@
1
1
  import { z } from 'zod/mini';
2
2
  import { ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } from './contract.js';
3
3
  /** Allowed characters for an app `name`. */ const APP_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
4
+ /**
5
+ * Dashboard visibility values. Mirrors `APP_VISIBILITIES` in `@sanity/cli-core`
6
+ * (which can't be imported here — pulling the barrel into this lean module bloats
7
+ * the config-load path). Kept in sync by a type test in `defineApp.test.ts`.
8
+ */ const APP_VISIBILITIES = [
9
+ 'default',
10
+ 'unlisted',
11
+ 'disabled'
12
+ ];
4
13
  /**
5
14
  * Internal application discriminator. Sanity-owned singleton apps only;
6
15
  * validated by the schema but excluded from the public `DefineAppInput` type.
@@ -53,17 +62,14 @@ import { ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } fr
53
62
  * application service on deploy, not into the app manifest. Service `name`s
54
63
  * must be unique within the app.
55
64
  */ services: z.optional(z.array(ServiceDeclarationSchema).check(z.refine((services)=>new Set(services.map((service)=>service.name)).size === services.length, 'Service `name` must be unique within an app'))),
56
- /**
57
- * Hostname the application is created at on first deploy. Generated when
58
- * omitted; redeploys target `deployment.appId` and ignore it. SDK apps
59
- * only — studios use `studioHost` in sanity.cli.ts.
60
- */ slug: z.optional(z.string()),
65
+ slug: z.string('App `slug` is required — the hostname the application is created at on deploy'),
61
66
  /** User-facing app title. Wins over studio.config.ts title on merge. */ title: z.string(),
62
67
  /**
63
68
  * Views the app exposes (e.g. dock panels). Metadata only — built into
64
69
  * render artifacts and persisted to the application service on deploy, not
65
70
  * into the app manifest. View `name`s must be unique within the app.
66
- */ views: z.optional(z.array(InterfaceDeclarationSchema).check(z.refine((views)=>new Set(views.map((view)=>view.name)).size === views.length, 'View `name` must be unique within an app')))
71
+ */ views: z.optional(z.array(InterfaceDeclarationSchema).check(z.refine((views)=>new Set(views.map((view)=>view.name)).size === views.length, 'View `name` must be unique within an app'))),
72
+ /** Dashboard visibility of the app. Defaults to `default` when omitted. */ visibility: z.optional(z.enum(APP_VISIBILITIES))
67
73
  }).check(// Studio app views are not implemented yet. A studio that declares `entry`
68
74
  // (the SDK app-view entrypoint) is rejected here rather than silently
69
75
  // generating one; studios keep navigating via their existing render path.
@@ -134,6 +140,7 @@ z.refine((input)=>!(input.config && !input.isSingleton), {
134
140
  isSingleton: true,
135
141
  name: 'media-library',
136
142
  organizationId: input.organizationId,
143
+ slug: 'media-library',
137
144
  title: 'Media Library'
138
145
  });
139
146
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\n\n/** Allowed characters for an app `name`. */\nconst APP_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/\n\n/**\n * Internal application discriminator. Sanity-owned singleton apps only;\n * validated by the schema but excluded from the public `DefineAppInput` type.\n */\nconst ApplicationType = z.enum(['coreApp', 'studio', 'canvas', 'dashboard', 'media-library'])\n\n/** Dock groups an app can place itself into. */\nconst DockGroupSchema = z.enum(['dock.system', 'dock.applications', 'dock.user'])\n\n/**\n * Dock group identifier. The API does not block a user app from declaring a\n * reserved group (e.g. `dock.system`); priority conventions keep Sanity-owned\n * apps ahead.\n * @public\n */\nexport type DockGroup = z.output<typeof DockGroupSchema>\n\n/**\n * Runtime-validation schema for `unstable_defineApp`. Validates the full shape\n * including the internal `applicationType`; the user-facing `DefineAppInput`\n * type below omits that field.\n * @internal\n */\nexport const DefineAppInputSchema = z\n .object({\n /**\n * Internal — Sanity-owned singleton apps only. Validated here but excluded\n * from the public `DefineAppInput` type.\n * @internal\n */\n applicationType: z.optional(ApplicationType),\n /**\n * Deployed as a versioned snapshot on the app's org installation, not the\n * application service. Singletons only. Internal, so excluded from the public\n * `DefineAppInput` and set via `@ts-expect-error` like `applicationType`.\n * @internal\n */\n config: z.optional(ConfigSchema),\n /**\n * App entrypoint module. Defaults to `./src/App.tsx` when omitted. The build\n * derives the app's navigable `app` view from it. SDK apps only — setting it\n * on a studio is rejected (studio app views are not yet implemented).\n */\n entry: z.optional(z.string()),\n /** Dock group to render in. Defaults to `dock.applications` when omitted. */\n group: z.optional(DockGroupSchema),\n /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */\n icon: z.optional(z.string()),\n /**\n * Sanity-owned app deployed once, installed per org; excluded from the public `DefineAppInput`.\n * @internal\n */\n isSingleton: z.optional(z.boolean()),\n /** Unique app identifier — must match `APP_NAME_PATTERN`. */\n name: z.string().check(z.regex(APP_NAME_PATTERN, 'App `name` must match /^[a-zA-Z0-9_-]+$/')),\n /** Organization that owns the app — the workbench runs and deploys against it. */\n organizationId: z.string(\n \"App `organizationId` is required — pass the owning organization's ID to `unstable_defineApp`\",\n ),\n /** Sort position within the group, ascending. Defaults to `100` when omitted. */\n priority: z.optional(z.number()),\n /**\n * Background services the app runs (e.g. a `worker` emitting dock badges).\n * Metadata only — built into worker artifacts and persisted to the\n * application service on deploy, not into the app manifest. Service `name`s\n * must be unique within the app.\n */\n services: z.optional(\n z\n .array(ServiceDeclarationSchema)\n .check(\n z.refine(\n (services) => new Set(services.map((service) => service.name)).size === services.length,\n 'Service `name` must be unique within an app',\n ),\n ),\n ),\n /**\n * Hostname the application is created at on first deploy. Generated when\n * omitted; redeploys target `deployment.appId` and ignore it. SDK apps\n * only — studios use `studioHost` in sanity.cli.ts.\n */\n slug: z.optional(z.string()),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /**\n * Views the app exposes (e.g. dock panels). Metadata only — built into\n * render artifacts and persisted to the application service on deploy, not\n * into the app manifest. View `name`s must be unique within the app.\n */\n views: z.optional(\n z\n .array(InterfaceDeclarationSchema)\n .check(\n z.refine(\n (views) => new Set(views.map((view) => view.name)).size === views.length,\n 'View `name` must be unique within an app',\n ),\n ),\n ),\n })\n .check(\n // Studio app views are not implemented yet. A studio that declares `entry`\n // (the SDK app-view entrypoint) is rejected here rather than silently\n // generating one; studios keep navigating via their existing render path.\n z.refine((input) => !(input.applicationType === 'studio' && input.entry !== undefined), {\n error: 'App views for studios are not implemented yet',\n path: ['entry'],\n }),\n )\n .check(\n // An config belongs to a Sanity-owned singleton (the Media\n // Library). A non-singleton declaring one is rejected — see\n // {@link readConfig} for the runtime guard.\n z.refine((input) => !(input.config && !input.isSingleton), {\n error: '`config` is only supported for singleton apps',\n path: ['config'],\n }),\n )\n\n/**\n * User-facing input for `unstable_defineApp`. Excludes the internal\n * `applicationType`, `isSingleton`, and `config` — validated by the\n * schema but not part of the public surface (Sanity-owned apps set them via\n * `@ts-expect-error`).\n * @public\n */\nexport type DefineAppInput = Omit<\n z.output<typeof DefineAppInputSchema>,\n 'applicationType' | 'config' | 'isSingleton'\n>\n\n/**\n * Nominal brand the CLI discriminates on to enable the workbench build/deploy\n * codepath. Registered via `Symbol.for` so the marker survives module-realm\n * boundaries — `@sanity/cli-core` re-derives the same global symbol with\n * `Symbol.for` rather than importing it, so it stays internal to this module.\n */\nconst WORKBENCH_APP: unique symbol = Symbol.for('sanity.workbench.defineApp')\n\n/**\n * The branded result of `unstable_defineApp`. Carries the same fields as the\n * input plus the internal brand — users only ever see `DefineAppInput`.\n * @public\n */\nexport interface DefineAppResult extends DefineAppInput {\n readonly [WORKBENCH_APP]: true\n}\n\n/**\n * A branded app as the CLI reads it — the full schema shape, including the\n * internal fields `DefineAppInput` omits. Schema-derived so the narrowing\n * can't drift from what the schema validates.\n * @public\n */\nexport type WorkbenchApp = DefineAppResult & z.output<typeof DefineAppInputSchema>\n\n/**\n * Whether `app` is a branded `unstable_defineApp(...)` result — the sole\n * workbench opt-in.\n * @public\n */\nexport function isWorkbenchApp(app: unknown): app is WorkbenchApp {\n return typeof app === 'object' && app !== null && WORKBENCH_APP in app\n}\n\n/**\n * The app's config, or `undefined` when it declares none. Throws\n * when a non-singleton declares one — configs belong to Sanity-owned singletons,\n * so build/dev/deploy all read it through here to reject the combination\n * consistently.\n * @internal\n */\nexport function readConfig(app: WorkbenchApp): WorkbenchApp['config'] | undefined {\n if (app.config && !app.isSingleton) {\n throw new Error('`config` is only supported for singleton apps')\n }\n return app.config\n}\n\n/**\n * Declare a Sanity Workbench application. Identity at runtime — returns the same\n * object reference, tagged with the workbench brand. Field validation (the\n * `name` pattern etc.) runs at build time in the CLI via `DefineAppInputSchema`;\n * this helper stays a thin, pure identity wrapper.\n * @public\n */\nexport function unstable_defineApp(input: DefineAppInput): DefineAppResult {\n return Object.defineProperty(input, WORKBENCH_APP, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n }) as DefineAppResult\n}\n\n/**\n * One custom field a media library exposes. `src` default-exports a `defineField(...)` schema type.\n * @public\n */\nexport interface MediaLibraryField {\n /** Unique within the media library. */\n name: string\n src: string\n title: string\n\n /** Readable outside the owning organization. */\n public?: boolean\n}\n\n/**\n * Sanity-owned singleton, so authors don't name or title the app — only `organizationId` is required.\n * @public\n */\nexport interface DefineMediaLibraryInput {\n /** Organization that owns the media library — the CLI runs and deploys against it. */\n organizationId: string\n\n fields?: MediaLibraryField[]\n}\n\n/**\n * Declare the Sanity Media Library as a workbench app — a singleton whose `fields` become its config.\n * @public\n */\nexport function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): DefineAppResult {\n return unstable_defineApp({\n // @ts-expect-error -- `applicationType`/`isSingleton`/`config` are internal, excluded from `DefineAppInput`; Sanity-owned apps set them\n applicationType: 'media-library',\n config: input.fields?.length ? {appType: 'media-library', fields: input.fields} : undefined,\n isSingleton: true,\n name: 'media-library',\n organizationId: input.organizationId,\n title: 'Media Library',\n })\n}\n"],"names":["z","ConfigSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_NAME_PATTERN","ApplicationType","enum","DockGroupSchema","DefineAppInputSchema","object","applicationType","optional","config","entry","string","group","icon","isSingleton","boolean","name","check","regex","organizationId","priority","number","services","array","refine","Set","map","service","size","length","slug","title","views","view","input","undefined","error","path","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","readConfig","Error","unstable_defineApp","Object","defineProperty","configurable","enumerable","value","writable","unstable_defineMediaLibrary","fields","appType"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\n\n/** Allowed characters for an app `name`. */\nconst APP_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/\n\n/**\n * Dashboard visibility values. Mirrors `APP_VISIBILITIES` in `@sanity/cli-core`\n * (which can't be imported here — pulling the barrel into this lean module bloats\n * the config-load path). Kept in sync by a type test in `defineApp.test.ts`.\n */\nconst APP_VISIBILITIES = ['default', 'unlisted', 'disabled'] as const\n\n/**\n * Internal application discriminator. Sanity-owned singleton apps only;\n * validated by the schema but excluded from the public `DefineAppInput` type.\n */\nconst ApplicationType = z.enum(['coreApp', 'studio', 'canvas', 'dashboard', 'media-library'])\n\n/** Dock groups an app can place itself into. */\nconst DockGroupSchema = z.enum(['dock.system', 'dock.applications', 'dock.user'])\n\n/**\n * Dock group identifier. The API does not block a user app from declaring a\n * reserved group (e.g. `dock.system`); priority conventions keep Sanity-owned\n * apps ahead.\n * @public\n */\nexport type DockGroup = z.output<typeof DockGroupSchema>\n\n/**\n * Runtime-validation schema for `unstable_defineApp`. Validates the full shape\n * including the internal `applicationType`; the user-facing `DefineAppInput`\n * type below omits that field.\n * @internal\n */\nexport const DefineAppInputSchema = z\n .object({\n /**\n * Internal — Sanity-owned singleton apps only. Validated here but excluded\n * from the public `DefineAppInput` type.\n * @internal\n */\n applicationType: z.optional(ApplicationType),\n /**\n * Deployed as a versioned snapshot on the app's org installation, not the\n * application service. Singletons only. Internal, so excluded from the public\n * `DefineAppInput` and set via `@ts-expect-error` like `applicationType`.\n * @internal\n */\n config: z.optional(ConfigSchema),\n /**\n * App entrypoint module. Defaults to `./src/App.tsx` when omitted. The build\n * derives the app's navigable `app` view from it. SDK apps only — setting it\n * on a studio is rejected (studio app views are not yet implemented).\n */\n entry: z.optional(z.string()),\n /** Dock group to render in. Defaults to `dock.applications` when omitted. */\n group: z.optional(DockGroupSchema),\n /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */\n icon: z.optional(z.string()),\n /**\n * Sanity-owned app deployed once, installed per org; excluded from the public `DefineAppInput`.\n * @internal\n */\n isSingleton: z.optional(z.boolean()),\n /** Unique app identifier — must match `APP_NAME_PATTERN`. */\n name: z.string().check(z.regex(APP_NAME_PATTERN, 'App `name` must match /^[a-zA-Z0-9_-]+$/')),\n /** Organization that owns the app — the workbench runs and deploys against it. */\n organizationId: z.string(\n \"App `organizationId` is required — pass the owning organization's ID to `unstable_defineApp`\",\n ),\n /** Sort position within the group, ascending. Defaults to `100` when omitted. */\n priority: z.optional(z.number()),\n /**\n * Background services the app runs (e.g. a `worker` emitting dock badges).\n * Metadata only — built into worker artifacts and persisted to the\n * application service on deploy, not into the app manifest. Service `name`s\n * must be unique within the app.\n */\n services: z.optional(\n z\n .array(ServiceDeclarationSchema)\n .check(\n z.refine(\n (services) => new Set(services.map((service) => service.name)).size === services.length,\n 'Service `name` must be unique within an app',\n ),\n ),\n ),\n slug: z.string('App `slug` is required — the hostname the application is created at on deploy'),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /**\n * Views the app exposes (e.g. dock panels). Metadata only — built into\n * render artifacts and persisted to the application service on deploy, not\n * into the app manifest. View `name`s must be unique within the app.\n */\n views: z.optional(\n z\n .array(InterfaceDeclarationSchema)\n .check(\n z.refine(\n (views) => new Set(views.map((view) => view.name)).size === views.length,\n 'View `name` must be unique within an app',\n ),\n ),\n ),\n /** Dashboard visibility of the app. Defaults to `default` when omitted. */\n visibility: z.optional(z.enum(APP_VISIBILITIES)),\n })\n .check(\n // Studio app views are not implemented yet. A studio that declares `entry`\n // (the SDK app-view entrypoint) is rejected here rather than silently\n // generating one; studios keep navigating via their existing render path.\n z.refine((input) => !(input.applicationType === 'studio' && input.entry !== undefined), {\n error: 'App views for studios are not implemented yet',\n path: ['entry'],\n }),\n )\n .check(\n // An config belongs to a Sanity-owned singleton (the Media\n // Library). A non-singleton declaring one is rejected — see\n // {@link readConfig} for the runtime guard.\n z.refine((input) => !(input.config && !input.isSingleton), {\n error: '`config` is only supported for singleton apps',\n path: ['config'],\n }),\n )\n\n/**\n * User-facing input for `unstable_defineApp`. Excludes the internal\n * `applicationType`, `isSingleton`, and `config` — validated by the\n * schema but not part of the public surface (Sanity-owned apps set them via\n * `@ts-expect-error`).\n * @public\n */\nexport type DefineAppInput = Omit<\n z.output<typeof DefineAppInputSchema>,\n 'applicationType' | 'config' | 'isSingleton'\n>\n\n/**\n * Nominal brand the CLI discriminates on to enable the workbench build/deploy\n * codepath. Registered via `Symbol.for` so the marker survives module-realm\n * boundaries — `@sanity/cli-core` re-derives the same global symbol with\n * `Symbol.for` rather than importing it, so it stays internal to this module.\n */\nconst WORKBENCH_APP: unique symbol = Symbol.for('sanity.workbench.defineApp')\n\n/**\n * The branded result of `unstable_defineApp`. Carries the same fields as the\n * input plus the internal brand — users only ever see `DefineAppInput`.\n * @public\n */\nexport interface DefineAppResult extends DefineAppInput {\n readonly [WORKBENCH_APP]: true\n}\n\n/**\n * A branded app as the CLI reads it — the full schema shape, including the\n * internal fields `DefineAppInput` omits. Schema-derived so the narrowing\n * can't drift from what the schema validates.\n * @public\n */\nexport type WorkbenchApp = DefineAppResult & z.output<typeof DefineAppInputSchema>\n\n/**\n * Whether `app` is a branded `unstable_defineApp(...)` result — the sole\n * workbench opt-in.\n * @public\n */\nexport function isWorkbenchApp(app: unknown): app is WorkbenchApp {\n return typeof app === 'object' && app !== null && WORKBENCH_APP in app\n}\n\n/**\n * The app's config, or `undefined` when it declares none. Throws\n * when a non-singleton declares one — configs belong to Sanity-owned singletons,\n * so build/dev/deploy all read it through here to reject the combination\n * consistently.\n * @internal\n */\nexport function readConfig(app: WorkbenchApp): WorkbenchApp['config'] | undefined {\n if (app.config && !app.isSingleton) {\n throw new Error('`config` is only supported for singleton apps')\n }\n return app.config\n}\n\n/**\n * Declare a Sanity Workbench application. Identity at runtime — returns the same\n * object reference, tagged with the workbench brand. Field validation (the\n * `name` pattern etc.) runs at build time in the CLI via `DefineAppInputSchema`;\n * this helper stays a thin, pure identity wrapper.\n * @public\n */\nexport function unstable_defineApp(input: DefineAppInput): DefineAppResult {\n return Object.defineProperty(input, WORKBENCH_APP, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n }) as DefineAppResult\n}\n\n/**\n * One custom field a media library exposes. `src` default-exports a `defineField(...)` schema type.\n * @public\n */\nexport interface MediaLibraryField {\n /** Unique within the media library. */\n name: string\n src: string\n title: string\n\n /** Readable outside the owning organization. */\n public?: boolean\n}\n\n/**\n * Sanity-owned singleton, so authors don't name or title the app — only `organizationId` is required.\n * @public\n */\nexport interface DefineMediaLibraryInput {\n /** Organization that owns the media library — the CLI runs and deploys against it. */\n organizationId: string\n\n fields?: MediaLibraryField[]\n}\n\n/**\n * Declare the Sanity Media Library as a workbench app — a singleton whose `fields` become its config.\n * @public\n */\nexport function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): DefineAppResult {\n return unstable_defineApp({\n // @ts-expect-error -- `applicationType`/`isSingleton`/`config` are internal, excluded from `DefineAppInput`; Sanity-owned apps set them\n applicationType: 'media-library',\n config: input.fields?.length ? {appType: 'media-library', fields: input.fields} : undefined,\n isSingleton: true,\n name: 'media-library',\n organizationId: input.organizationId,\n slug: 'media-library',\n title: 'Media Library',\n })\n}\n"],"names":["z","ConfigSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_NAME_PATTERN","APP_VISIBILITIES","ApplicationType","enum","DockGroupSchema","DefineAppInputSchema","object","applicationType","optional","config","entry","string","group","icon","isSingleton","boolean","name","check","regex","organizationId","priority","number","services","array","refine","Set","map","service","size","length","slug","title","views","view","visibility","input","undefined","error","path","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","readConfig","Error","unstable_defineApp","Object","defineProperty","configurable","enumerable","value","writable","unstable_defineMediaLibrary","fields","appType"],"mappings":"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"}
@@ -14,11 +14,13 @@ import { isWorkbenchApp, readConfig } from './defineApp.js';
14
14
  applicationType: app.applicationType,
15
15
  config: readConfig(app),
16
16
  entry: app.entry,
17
+ icon: app.icon,
17
18
  isSingleton: app.isSingleton,
18
19
  name: app.name,
19
20
  services: app.services ?? [],
20
21
  slug: app.slug,
21
- views: app.views ?? []
22
+ views: app.views ?? [],
23
+ visibility: app.visibility
22
24
  };
23
25
  }
24
26
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resolveWorkbenchApp.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `unstable_defineApp` app into its declared interfaces, or `null` for a plain\n// project. The build and deploy accessors (actions/build, actions/deploy) each\n// build their command-specific view on top of this one brand-check +\n// extraction, so the discrimination lives in exactly one place.\n\nimport {type CliConfig} from '@sanity/cli-core'\n\nimport {type DefineAppInput, isWorkbenchApp, readConfig, type WorkbenchApp} from './defineApp.js'\n\n/**\n * Bundled so adding a declaration family touches this type and the artifact\n * expanders, not every hop of build/dev plumbing in between.\n * @internal\n */\nexport interface WorkbenchExposes {\n config?: WorkbenchApp['config']\n services?: DefineAppInput['services']\n views?: DefineAppInput['views']\n}\n\n/** @public */\nexport interface ResolvedWorkbenchApp {\n /** The app's unique `name` from `unstable_defineApp`. */\n readonly name: string\n /** Background worker services the app declares. */\n readonly services: NonNullable<DefineAppInput['services']>\n\n /** Dock panel views the app declares. */\n readonly views: NonNullable<DefineAppInput['views']>\n\n /** Resolved app kind — `studio` or one of the SDK app types. */\n readonly applicationType?: string\n /** Deploys on its own path, separate from the interfaces. */\n readonly config?: WorkbenchApp['config']\n /** SDK app-view entrypoint, when declared. */\n readonly entry?: string\n /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */\n readonly isSingleton?: boolean\n /** Hostname the application is created at on first deploy. */\n readonly slug?: string\n}\n\n/**\n * Resolve the workbench app for a CLI config, or `null` for a plain project.\n * @public\n */\nexport function resolveWorkbenchApp(\n cliConfig: CliConfig | null | undefined,\n): ResolvedWorkbenchApp | null {\n const app = cliConfig?.app\n if (!isWorkbenchApp(app)) return null\n\n return {\n applicationType: app.applicationType,\n config: readConfig(app),\n entry: app.entry,\n isSingleton: app.isSingleton,\n name: app.name,\n services: app.services ?? [],\n slug: app.slug,\n views: app.views ?? [],\n }\n}\n"],"names":["isWorkbenchApp","readConfig","resolveWorkbenchApp","cliConfig","app","applicationType","config","entry","isSingleton","name","services","slug","views"],"mappings":"AAAA,gEAAgE;AAChE,+EAA+E;AAC/E,+EAA+E;AAC/E,qEAAqE;AACrE,gEAAgE;AAIhE,SAA6BA,cAAc,EAAEC,UAAU,QAA0B,iBAAgB;AAmCjG;;;CAGC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,IAAI,CAACJ,eAAeI,MAAM,OAAO;IAEjC,OAAO;QACLC,iBAAiBD,IAAIC,eAAe;QACpCC,QAAQL,WAAWG;QACnBG,OAAOH,IAAIG,KAAK;QAChBC,aAAaJ,IAAII,WAAW;QAC5BC,MAAML,IAAIK,IAAI;QACdC,UAAUN,IAAIM,QAAQ,IAAI,EAAE;QAC5BC,MAAMP,IAAIO,IAAI;QACdC,OAAOR,IAAIQ,KAAK,IAAI,EAAE;IACxB;AACF"}
1
+ {"version":3,"sources":["../src/resolveWorkbenchApp.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `unstable_defineApp` app into its declared interfaces, or `null` for a plain\n// project. The build and deploy accessors (actions/build, actions/deploy) each\n// build their command-specific view on top of this one brand-check +\n// extraction, so the discrimination lives in exactly one place.\n\nimport {type AppVisibility, type CliConfig} from '@sanity/cli-core'\n\nimport {type DefineAppInput, isWorkbenchApp, readConfig, type WorkbenchApp} from './defineApp.js'\n\n/**\n * Bundled so adding a declaration family touches this type and the artifact\n * expanders, not every hop of build/dev plumbing in between.\n * @internal\n */\nexport interface WorkbenchExposes {\n config?: WorkbenchApp['config']\n services?: DefineAppInput['services']\n views?: DefineAppInput['views']\n}\n\n/** @public */\nexport interface ResolvedWorkbenchApp {\n /** The app's unique `name` from `unstable_defineApp`. */\n readonly name: string\n /** Background worker services the app declares. */\n readonly services: NonNullable<DefineAppInput['services']>\n\n /** Dock panel views the app declares. */\n readonly views: NonNullable<DefineAppInput['views']>\n\n /** Resolved app kind — `studio` or one of the SDK app types. */\n readonly applicationType?: string\n /** Deploys on its own path, separate from the interfaces. */\n readonly config?: WorkbenchApp['config']\n /** SDK app-view entrypoint, when declared. */\n readonly entry?: string\n /** Path to the app's icon SVG, resolved and shipped to Brett on deploy. */\n readonly icon?: string\n /** Explicit singleton flag (a Sanity-owned app); `undefined` when the app doesn't set it. */\n readonly isSingleton?: boolean\n /** Hostname the application is created at on first deploy. */\n readonly slug?: string\n /** Dashboard visibility declared by the app; `undefined` when unset. */\n readonly visibility?: AppVisibility\n}\n\n/**\n * Resolve the workbench app for a CLI config, or `null` for a plain project.\n * @public\n */\nexport function resolveWorkbenchApp(\n cliConfig: CliConfig | null | undefined,\n): ResolvedWorkbenchApp | null {\n const app = cliConfig?.app\n if (!isWorkbenchApp(app)) return null\n\n return {\n applicationType: app.applicationType,\n config: readConfig(app),\n entry: app.entry,\n icon: app.icon,\n isSingleton: app.isSingleton,\n name: app.name,\n services: app.services ?? [],\n slug: app.slug,\n views: app.views ?? [],\n visibility: app.visibility,\n }\n}\n"],"names":["isWorkbenchApp","readConfig","resolveWorkbenchApp","cliConfig","app","applicationType","config","entry","icon","isSingleton","name","services","slug","views","visibility"],"mappings":"AAAA,gEAAgE;AAChE,+EAA+E;AAC/E,+EAA+E;AAC/E,qEAAqE;AACrE,gEAAgE;AAIhE,SAA6BA,cAAc,EAAEC,UAAU,QAA0B,iBAAgB;AAuCjG;;;CAGC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,IAAI,CAACJ,eAAeI,MAAM,OAAO;IAEjC,OAAO;QACLC,iBAAiBD,IAAIC,eAAe;QACpCC,QAAQL,WAAWG;QACnBG,OAAOH,IAAIG,KAAK;QAChBC,MAAMJ,IAAII,IAAI;QACdC,aAAaL,IAAIK,WAAW;QAC5BC,MAAMN,IAAIM,IAAI;QACdC,UAAUP,IAAIO,QAAQ,IAAI,EAAE;QAC5BC,MAAMR,IAAIQ,IAAI;QACdC,OAAOT,IAAIS,KAAK,IAAI,EAAE;QACtBC,YAAYV,IAAIU,UAAU;IAC5B;AACF"}
@@ -28,19 +28,22 @@ export async function getApplication(applicationId) {
28
28
  }
29
29
  }
30
30
  /** Create an application and its first deployment in one call. */ export async function createApplication(options) {
31
- const { interfaces, isSingleton, organizationId, projectId, slug, tarball, title, type, version, workspaces } = options;
31
+ const { icon, interfaces, isSingleton, organizationId, projectId, slug, tarball, title, type, version, visibility, workspaces } = options;
32
32
  const formData = new FormData();
33
33
  formData.append('type', type);
34
34
  formData.append('title', title);
35
35
  formData.append('organizationId', organizationId);
36
36
  formData.append('slug', slug);
37
37
  if (isSingleton !== undefined) formData.append('isSingleton', String(isSingleton));
38
+ if (visibility) formData.append('visibility', visibility);
38
39
  // Studio config is set once, at create — it's immutable on redeploy.
39
40
  if (projectId) appendJson(formData, 'config', {
40
41
  studio: {
41
42
  projectId
42
43
  }
43
44
  });
45
+ // Application-level JSON part, independent of the deployment.
46
+ if (icon) appendJson(formData, 'icon', icon);
44
47
  appendDeploymentParts(formData, {
45
48
  interfaces,
46
49
  tarball,
@@ -49,6 +52,17 @@ export async function getApplication(applicationId) {
49
52
  });
50
53
  return request(`/applications`, formData);
51
54
  }
55
+ /**
56
+ * Patch an application's mutable fields. The deploy endpoint ignores these, so a
57
+ * redeploy syncs the title (and icon) from config here alongside the new deployment.
58
+ */ export async function updateApplication(applicationId, update) {
59
+ const client = await getClient();
60
+ await client.request({
61
+ body: update,
62
+ method: 'PATCH',
63
+ uri: `/applications/${applicationId}`
64
+ });
65
+ }
52
66
  /** Deploy a new active version to an existing application. */ export async function createDeployment(options) {
53
67
  const { applicationId, interfaces, isAutoUpdating, tarball, version, workspaces } = options;
54
68
  const formData = new FormData();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/applications.ts"],"sourcesContent":["import {PassThrough} from 'node:stream'\nimport {type Gzip} from 'node:zlib'\n\nimport {getGlobalCliClient} from '@sanity/cli-core'\nimport {isStaging} from '@sanity/cli-core/util'\nimport FormData from 'form-data'\n\nimport {APP_WORKBENCH_API_VERSION} from './apiVersion.js'\n\nexport type ApplicationType = 'coreApp' | 'studio'\n\nexport interface Application {\n id: string\n organizationId: string\n slug: string | null\n title: string\n type: ApplicationType\n}\n\n/**\n * An interface as Brett stores it: the declared `type` (validated server-side,\n * not here) and the remote-relative `moduleId` the workbench loads it by — the\n * host prepends the app's own id.\n * @internal\n */\nexport interface BrettInterface {\n moduleId: string\n name: string\n title: string\n type: string\n version: string\n}\n\n/** A studio workspace as Brett stores it. */\nexport interface BrettWorkspace {\n dataset: string\n projectId: string\n\n basePath?: string\n icon?: string\n name?: string\n subtitle?: string\n title?: string\n}\n\nexport function getWorkbenchUrl(organizationId: string): string {\n return `https://${organizationId}.${isStaging() ? 'run.sanity.work' : 'sanity.run'}`\n}\n\n/** Where a deployed application is served on its organization's workbench. */\nexport function getApplicationUrl(\n application: Pick<Application, 'id' | 'organizationId' | 'type'>,\n): string {\n const segment = application.type === 'studio' ? 'studio' : 'application'\n return `${getWorkbenchUrl(application.organizationId)}/${segment}/${application.id}`\n}\n\nasync function getClient() {\n return getGlobalCliClient({apiVersion: APP_WORKBENCH_API_VERSION, requireUser: true})\n}\n\nexport async function getApplication(applicationId: string): Promise<Application | null> {\n const client = await getClient()\n try {\n return await client.request({uri: `/applications/${applicationId}`})\n } catch (err) {\n if ((err as {statusCode?: number})?.statusCode === 404) return null\n throw err\n }\n}\n\n/** Create an application and its first deployment in one call. */\nexport async function createApplication(options: {\n interfaces: readonly BrettInterface[]\n isSingleton?: boolean\n organizationId: string\n projectId?: string\n slug: string\n tarball: Gzip\n title: string\n type: ApplicationType\n version: string\n workspaces?: readonly BrettWorkspace[]\n}): Promise<Application> {\n const {\n interfaces,\n isSingleton,\n organizationId,\n projectId,\n slug,\n tarball,\n title,\n type,\n version,\n workspaces,\n } = options\n const formData = new FormData()\n formData.append('type', type)\n formData.append('title', title)\n formData.append('organizationId', organizationId)\n formData.append('slug', slug)\n if (isSingleton !== undefined) formData.append('isSingleton', String(isSingleton))\n // Studio config is set once, at create — it's immutable on redeploy.\n if (projectId) appendJson(formData, 'config', {studio: {projectId}})\n appendDeploymentParts(formData, {interfaces, tarball, version, workspaces})\n return request(`/applications`, formData)\n}\n\n/** Deploy a new active version to an existing application. */\nexport async function createDeployment(options: {\n applicationId: string\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n tarball: Gzip\n version: string\n workspaces?: readonly BrettWorkspace[]\n}): Promise<{id: string}> {\n const {applicationId, interfaces, isAutoUpdating, tarball, version, workspaces} = options\n const formData = new FormData()\n formData.append('isAutoUpdating', isAutoUpdating.toString())\n appendDeploymentParts(formData, {interfaces, tarball, version, workspaces})\n return request(`/applications/${applicationId}/deployments`, formData)\n}\n\n/** Soft-deletes the application and all its deployments; already deleted counts as done. */\nexport async function deleteApplication(applicationId: string): Promise<void> {\n const client = await getClient()\n try {\n await client.request({method: 'DELETE', uri: `/applications/${applicationId}`})\n } catch (err) {\n if ((err as {statusCode?: number})?.statusCode !== 404) throw err\n }\n}\n\nfunction appendDeploymentParts(\n formData: FormData,\n {\n interfaces,\n tarball,\n version,\n workspaces,\n }: {\n interfaces: readonly BrettInterface[]\n tarball: Gzip\n version: string\n workspaces?: readonly BrettWorkspace[]\n },\n): void {\n formData.append('version', version)\n appendJson(formData, 'interfaces', interfaces)\n // Studio-only — the server rejects a workspaces part on non-studio types.\n if (workspaces?.length) appendJson(formData, 'workspaces', workspaces)\n formData.append('tarball', tarball, {contentType: 'application/gzip', filename: 'app.tar.gz'})\n}\n\n/** Structured parts must arrive as JSON so the server parses them. */\nfunction appendJson(formData: FormData, name: string, value: unknown): void {\n formData.append(name, JSON.stringify(value), {contentType: 'application/json'})\n}\n\nasync function request<T>(uri: string, formData: FormData): Promise<T> {\n const client = await getClient()\n return client.request({\n body: formData.pipe(new PassThrough()),\n headers: formData.getHeaders(),\n method: 'POST',\n uri,\n })\n}\n"],"names":["PassThrough","getGlobalCliClient","isStaging","FormData","APP_WORKBENCH_API_VERSION","getWorkbenchUrl","organizationId","getApplicationUrl","application","segment","type","id","getClient","apiVersion","requireUser","getApplication","applicationId","client","request","uri","err","statusCode","createApplication","options","interfaces","isSingleton","projectId","slug","tarball","title","version","workspaces","formData","append","undefined","String","appendJson","studio","appendDeploymentParts","createDeployment","isAutoUpdating","toString","deleteApplication","method","length","contentType","filename","name","value","JSON","stringify","body","pipe","headers","getHeaders"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/applications.ts"],"sourcesContent":["import {PassThrough} from 'node:stream'\nimport {type Gzip} from 'node:zlib'\n\nimport {type AppVisibility, getGlobalCliClient} from '@sanity/cli-core'\nimport {isStaging} from '@sanity/cli-core/util'\nimport FormData from 'form-data'\n\nimport {type AppInterfaceMetadata} from '../contract.js'\nimport {APP_WORKBENCH_API_VERSION} from './apiVersion.js'\n\nexport type ApplicationType = 'coreApp' | 'studio'\n\nexport interface Application {\n id: string\n organizationId: string\n slug: string | null\n title: string\n type: ApplicationType\n}\n\ninterface BrettInterfaceBase {\n moduleId: string\n name: string\n title: string\n version: string\n}\n\n/**\n * An interface as Brett stores it, discriminated on `type`. `moduleId` is\n * remote-relative — the host prepends the app's id. Brett assigns the id.\n * @internal\n */\nexport type BrettInterface =\n | (BrettInterfaceBase & {metadata: AppInterfaceMetadata | null; type: 'app'})\n | (BrettInterfaceBase & {metadata: null; type: 'panel'})\n | (BrettInterfaceBase & {metadata: null; type: 'worker'})\n\n/** A studio workspace as Brett stores it. */\nexport interface BrettWorkspace {\n dataset: string\n projectId: string\n\n basePath?: string\n icon?: string\n name?: string\n subtitle?: string\n title?: string\n}\n\nexport function getWorkbenchUrl(organizationId: string): string {\n return `https://${organizationId}.${isStaging() ? 'run.sanity.work' : 'sanity.run'}`\n}\n\n/** Where a deployed application is served on its organization's workbench. */\nexport function getApplicationUrl(\n application: Pick<Application, 'id' | 'organizationId' | 'type'>,\n): string {\n const segment = application.type === 'studio' ? 'studio' : 'application'\n return `${getWorkbenchUrl(application.organizationId)}/${segment}/${application.id}`\n}\n\nasync function getClient() {\n return getGlobalCliClient({apiVersion: APP_WORKBENCH_API_VERSION, requireUser: true})\n}\n\nexport async function getApplication(applicationId: string): Promise<Application | null> {\n const client = await getClient()\n try {\n return await client.request({uri: `/applications/${applicationId}`})\n } catch (err) {\n if ((err as {statusCode?: number})?.statusCode === 404) return null\n throw err\n }\n}\n\n/** Create an application and its first deployment in one call. */\nexport async function createApplication(options: {\n icon?: string\n interfaces: readonly BrettInterface[]\n isSingleton?: boolean\n organizationId: string\n projectId?: string\n slug: string\n tarball: Gzip\n title: string\n type: ApplicationType\n version: string\n visibility?: AppVisibility\n workspaces?: readonly BrettWorkspace[]\n}): Promise<Application> {\n const {\n icon,\n interfaces,\n isSingleton,\n organizationId,\n projectId,\n slug,\n tarball,\n title,\n type,\n version,\n visibility,\n workspaces,\n } = options\n const formData = new FormData()\n formData.append('type', type)\n formData.append('title', title)\n formData.append('organizationId', organizationId)\n formData.append('slug', slug)\n if (isSingleton !== undefined) formData.append('isSingleton', String(isSingleton))\n if (visibility) formData.append('visibility', visibility)\n // Studio config is set once, at create — it's immutable on redeploy.\n if (projectId) appendJson(formData, 'config', {studio: {projectId}})\n // Application-level JSON part, independent of the deployment.\n if (icon) appendJson(formData, 'icon', icon)\n appendDeploymentParts(formData, {interfaces, tarball, version, workspaces})\n return request(`/applications`, formData)\n}\n\n/** Mutable application fields the deploy flow patches after create. */\nexport interface ApplicationUpdate {\n icon?: string | null\n title?: string\n}\n\n/**\n * Patch an application's mutable fields. The deploy endpoint ignores these, so a\n * redeploy syncs the title (and icon) from config here alongside the new deployment.\n */\nexport async function updateApplication(\n applicationId: string,\n update: ApplicationUpdate,\n): Promise<void> {\n const client = await getClient()\n await client.request({body: update, method: 'PATCH', uri: `/applications/${applicationId}`})\n}\n\n/** Deploy a new active version to an existing application. */\nexport async function createDeployment(options: {\n applicationId: string\n interfaces: readonly BrettInterface[]\n isAutoUpdating: boolean\n tarball: Gzip\n version: string\n workspaces?: readonly BrettWorkspace[]\n}): Promise<{id: string}> {\n const {applicationId, interfaces, isAutoUpdating, tarball, version, workspaces} = options\n const formData = new FormData()\n formData.append('isAutoUpdating', isAutoUpdating.toString())\n appendDeploymentParts(formData, {interfaces, tarball, version, workspaces})\n return request(`/applications/${applicationId}/deployments`, formData)\n}\n\n/** Soft-deletes the application and all its deployments; already deleted counts as done. */\nexport async function deleteApplication(applicationId: string): Promise<void> {\n const client = await getClient()\n try {\n await client.request({method: 'DELETE', uri: `/applications/${applicationId}`})\n } catch (err) {\n if ((err as {statusCode?: number})?.statusCode !== 404) throw err\n }\n}\n\nfunction appendDeploymentParts(\n formData: FormData,\n {\n interfaces,\n tarball,\n version,\n workspaces,\n }: {\n interfaces: readonly BrettInterface[]\n tarball: Gzip\n version: string\n workspaces?: readonly BrettWorkspace[]\n },\n): void {\n formData.append('version', version)\n appendJson(formData, 'interfaces', interfaces)\n // Studio-only — the server rejects a workspaces part on non-studio types.\n if (workspaces?.length) appendJson(formData, 'workspaces', workspaces)\n formData.append('tarball', tarball, {contentType: 'application/gzip', filename: 'app.tar.gz'})\n}\n\n/** Structured parts must arrive as JSON so the server parses them. */\nfunction appendJson(formData: FormData, name: string, value: unknown): void {\n formData.append(name, JSON.stringify(value), {contentType: 'application/json'})\n}\n\nasync function request<T>(uri: string, formData: FormData): Promise<T> {\n const client = await getClient()\n return client.request({\n body: formData.pipe(new PassThrough()),\n headers: formData.getHeaders(),\n method: 'POST',\n uri,\n })\n}\n"],"names":["PassThrough","getGlobalCliClient","isStaging","FormData","APP_WORKBENCH_API_VERSION","getWorkbenchUrl","organizationId","getApplicationUrl","application","segment","type","id","getClient","apiVersion","requireUser","getApplication","applicationId","client","request","uri","err","statusCode","createApplication","options","icon","interfaces","isSingleton","projectId","slug","tarball","title","version","visibility","workspaces","formData","append","undefined","String","appendJson","studio","appendDeploymentParts","updateApplication","update","body","method","createDeployment","isAutoUpdating","toString","deleteApplication","length","contentType","filename","name","value","JSON","stringify","pipe","headers","getHeaders"],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /** How long teardown may run before we stop waiting and force the process to
2
+ * exit — long enough for Vite servers and watchers to close, short enough not to
3
+ * strand a backgrounded process. */ const SHUTDOWN_GRACE_MS = 5000;
4
+ /**
5
+ * Map a server's bind address to a host that's safe to show in a URL. Bind-only
6
+ * addresses ('0.0.0.0', '::') aren't routable in every browser (notably on
7
+ * Windows), so fall back to localhost for display. The bind address itself is
8
+ * untouched — this only affects the URL printed to the user.
9
+ */ export function toDisplayHost(host) {
10
+ if (!host || host === '0.0.0.0' || host === '::' || host === '[::]') {
11
+ return 'localhost';
12
+ }
13
+ return host;
14
+ }
15
+ /**
16
+ * Shuts down a command that runs several long-lived servers at once. Both
17
+ * `sanity dev` and `sanity start` start a workbench shell, an app remote, and a
18
+ * registry entry, and every one of them has to be stopped again — on a clean
19
+ * exit, on a startup error, or when the user presses Ctrl-C.
20
+ *
21
+ * How it works:
22
+ * - Each server adds its own shutdown function to `closers` as it starts.
23
+ * - `close()` runs them in reverse (last started, first stopped), and only
24
+ * runs them once no matter how many times it's called.
25
+ * - `installSignalHandlers()` makes Ctrl-C / kill trigger that same `close()`.
26
+ *
27
+ * Signals need care: Node would normally exit the instant one arrives, but our
28
+ * shutdown is async. So we catch the signal, run `close()`, and only then send
29
+ * the signal on again so the process exits with its usual code. A timer is the
30
+ * escape hatch — if shutdown ever hangs, it forces the exit rather than leaving
31
+ * the process stuck.
32
+ */ export function createServerLifecycle() {
33
+ const closers = [];
34
+ const runClosers = async ()=>{
35
+ // Reverse order, so each server is stopped before the one it was started on
36
+ // top of. A closer that throws is ignored so one failure can't block the rest.
37
+ for (const closeResource of closers.splice(0).toReversed()){
38
+ await closeResource().catch(()=>{});
39
+ }
40
+ };
41
+ // `close` can be called more than once — a startup error and then a Ctrl-C, or
42
+ // two signals racing. Keep the first call's promise and hand it back to the
43
+ // rest, so everything is torn down exactly once.
44
+ let teardown;
45
+ const close = ()=>{
46
+ teardown ??= (async ()=>{
47
+ process.off('SIGINT', onSignal);
48
+ process.off('SIGTERM', onSignal);
49
+ await runClosers();
50
+ })();
51
+ return teardown;
52
+ };
53
+ function onSignal(signal) {
54
+ // Force the exit if shutdown doesn't finish in time, so a wedged server
55
+ // can't hang the process forever.
56
+ const graceTimer = setTimeout(()=>process.kill(process.pid, signal), SHUTDOWN_GRACE_MS);
57
+ graceTimer.unref();
58
+ // Tear down first, then re-send the signal so the process exits with the
59
+ // code it normally would for this signal.
60
+ void close().finally(()=>{
61
+ clearTimeout(graceTimer);
62
+ process.kill(process.pid, signal);
63
+ });
64
+ }
65
+ return {
66
+ close,
67
+ closers,
68
+ installSignalHandlers () {
69
+ process.once('SIGINT', onSignal);
70
+ process.once('SIGTERM', onSignal);
71
+ }
72
+ };
73
+ }
74
+
75
+ //# sourceMappingURL=serverOrchestration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/serverOrchestration.ts"],"sourcesContent":["/** How long teardown may run before we stop waiting and force the process to\n * exit — long enough for Vite servers and watchers to close, short enough not to\n * strand a backgrounded process. */\nconst SHUTDOWN_GRACE_MS = 5000\n\n/**\n * Map a server's bind address to a host that's safe to show in a URL. Bind-only\n * addresses ('0.0.0.0', '::') aren't routable in every browser (notably on\n * Windows), so fall back to localhost for display. The bind address itself is\n * untouched — this only affects the URL printed to the user.\n */\nexport function toDisplayHost(host: string | undefined): string {\n if (!host || host === '0.0.0.0' || host === '::' || host === '[::]') {\n return 'localhost'\n }\n return host\n}\n\nexport interface ServerLifecycle {\n /** Tear everything down exactly once and stop listening for signals. Safe to call more than once. */\n close: () => Promise<void>\n /**\n * Shutdown functions, one per server/resource. Push one as each resource\n * starts; `close` unwinds them in reverse. A throwing closer is swallowed so\n * one bad teardown can't strand the rest.\n */\n closers: Array<() => Promise<void>>\n /** Begin handling Ctrl-C / kill by tearing down, then re-raising the signal so the process still exits. */\n installSignalHandlers: () => void\n}\n\n/**\n * Shuts down a command that runs several long-lived servers at once. Both\n * `sanity dev` and `sanity start` start a workbench shell, an app remote, and a\n * registry entry, and every one of them has to be stopped again — on a clean\n * exit, on a startup error, or when the user presses Ctrl-C.\n *\n * How it works:\n * - Each server adds its own shutdown function to `closers` as it starts.\n * - `close()` runs them in reverse (last started, first stopped), and only\n * runs them once no matter how many times it's called.\n * - `installSignalHandlers()` makes Ctrl-C / kill trigger that same `close()`.\n *\n * Signals need care: Node would normally exit the instant one arrives, but our\n * shutdown is async. So we catch the signal, run `close()`, and only then send\n * the signal on again so the process exits with its usual code. A timer is the\n * escape hatch — if shutdown ever hangs, it forces the exit rather than leaving\n * the process stuck.\n */\nexport function createServerLifecycle(): ServerLifecycle {\n const closers: ServerLifecycle['closers'] = []\n\n const runClosers = async () => {\n // Reverse order, so each server is stopped before the one it was started on\n // top of. A closer that throws is ignored so one failure can't block the rest.\n for (const closeResource of closers.splice(0).toReversed()) {\n await closeResource().catch(() => {})\n }\n }\n\n // `close` can be called more than once — a startup error and then a Ctrl-C, or\n // two signals racing. Keep the first call's promise and hand it back to the\n // rest, so everything is torn down exactly once.\n let teardown: Promise<void> | undefined\n const close = () => {\n teardown ??= (async () => {\n process.off('SIGINT', onSignal)\n process.off('SIGTERM', onSignal)\n await runClosers()\n })()\n return teardown\n }\n\n function onSignal(signal: NodeJS.Signals) {\n // Force the exit if shutdown doesn't finish in time, so a wedged server\n // can't hang the process forever.\n const graceTimer = setTimeout(() => process.kill(process.pid, signal), SHUTDOWN_GRACE_MS)\n graceTimer.unref()\n // Tear down first, then re-send the signal so the process exits with the\n // code it normally would for this signal.\n void close().finally(() => {\n clearTimeout(graceTimer)\n process.kill(process.pid, signal)\n })\n }\n\n return {\n close,\n closers,\n installSignalHandlers() {\n process.once('SIGINT', onSignal)\n process.once('SIGTERM', onSignal)\n },\n }\n}\n"],"names":["SHUTDOWN_GRACE_MS","toDisplayHost","host","createServerLifecycle","closers","runClosers","closeResource","splice","toReversed","catch","teardown","close","process","off","onSignal","signal","graceTimer","setTimeout","kill","pid","unref","finally","clearTimeout","installSignalHandlers","once"],"mappings":"AAAA;;kCAEkC,GAClC,MAAMA,oBAAoB;AAE1B;;;;;CAKC,GACD,OAAO,SAASC,cAAcC,IAAwB;IACpD,IAAI,CAACA,QAAQA,SAAS,aAAaA,SAAS,QAAQA,SAAS,QAAQ;QACnE,OAAO;IACT;IACA,OAAOA;AACT;AAeA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC;IACd,MAAMC,UAAsC,EAAE;IAE9C,MAAMC,aAAa;QACjB,4EAA4E;QAC5E,+EAA+E;QAC/E,KAAK,MAAMC,iBAAiBF,QAAQG,MAAM,CAAC,GAAGC,UAAU,GAAI;YAC1D,MAAMF,gBAAgBG,KAAK,CAAC,KAAO;QACrC;IACF;IAEA,+EAA+E;IAC/E,4EAA4E;IAC5E,iDAAiD;IACjD,IAAIC;IACJ,MAAMC,QAAQ;QACZD,aAAa,AAAC,CAAA;YACZE,QAAQC,GAAG,CAAC,UAAUC;YACtBF,QAAQC,GAAG,CAAC,WAAWC;YACvB,MAAMT;QACR,CAAA;QACA,OAAOK;IACT;IAEA,SAASI,SAASC,MAAsB;QACtC,wEAAwE;QACxE,kCAAkC;QAClC,MAAMC,aAAaC,WAAW,IAAML,QAAQM,IAAI,CAACN,QAAQO,GAAG,EAAEJ,SAASf;QACvEgB,WAAWI,KAAK;QAChB,yEAAyE;QACzE,0CAA0C;QAC1C,KAAKT,QAAQU,OAAO,CAAC;YACnBC,aAAaN;YACbJ,QAAQM,IAAI,CAACN,QAAQO,GAAG,EAAEJ;QAC5B;IACF;IAEA,OAAO;QACLJ;QACAP;QACAmB;YACEX,QAAQY,IAAI,CAAC,UAAUV;YACvBF,QAAQY,IAAI,CAAC,WAAWV;QAC1B;IACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workbench-cli",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Internal implementation detail of the Sanity CLI's unstable workbench support. Not intended for direct use.",
5
5
  "homepage": "https://github.com/sanity-io/cli",
6
6
  "bugs": "https://github.com/sanity-io/cli/issues",
@@ -39,6 +39,10 @@
39
39
  "source": "./src/_exports/init.ts",
40
40
  "default": "./dist/_exports/init.js"
41
41
  },
42
+ "./preview": {
43
+ "source": "./src/_exports/preview.ts",
44
+ "default": "./dist/_exports/preview.js"
45
+ },
42
46
  "./undeploy": {
43
47
  "source": "./src/_exports/undeploy.ts",
44
48
  "default": "./dist/_exports/undeploy.js"
@@ -49,35 +53,35 @@
49
53
  "access": "public"
50
54
  },
51
55
  "dependencies": {
52
- "@module-federation/vite": "1.16.14",
56
+ "@module-federation/vite": "1.18.1",
53
57
  "@vitejs/plugin-react": "^6.0.3",
54
58
  "form-data": "^4.0.5",
55
59
  "tar-fs": "^3.1.2",
56
- "vite": "^8.1.3",
60
+ "vite": "^8.1.5",
57
61
  "zod": "^4.4.3",
58
- "@sanity/cli-core": "^2.4.0"
62
+ "@sanity/cli-core": "^2.5.1"
59
63
  },
60
64
  "devDependencies": {
61
65
  "@eslint/compat": "^2.1.0",
62
- "@sanity/pkg-utils": "^10.8.1",
66
+ "@sanity/pkg-utils": "^11.0.9",
63
67
  "@swc/cli": "^0.8.1",
64
- "@swc/core": "^1.15.41",
68
+ "@swc/core": "^1.15.43",
65
69
  "@types/node": "^22.20.0",
66
70
  "@types/tar-fs": "^2.0.4",
67
- "@vitest/coverage-istanbul": "^4.1.9",
68
- "eslint": "^10.4.1",
71
+ "@vitest/coverage-istanbul": "^4.1.10",
72
+ "eslint": "^10.7.0",
69
73
  "publint": "^0.3.21",
70
- "typescript": "^5.9.3",
71
- "vitest": "^4.1.9",
74
+ "typescript": "^6.0.3",
75
+ "vitest": "^4.1.10",
72
76
  "@repo/package.config": "0.0.1",
73
77
  "@repo/tsconfig": "3.70.0",
74
- "@sanity/eslint-config-cli": "^1.1.2"
78
+ "@sanity/eslint-config-cli": "^1.1.3"
75
79
  },
76
80
  "engines": {
77
81
  "node": ">=22.12"
78
82
  },
79
83
  "scripts": {
80
- "build": "swc --delete-dir-on-start --strip-leading-paths --out-dir dist/ src --ignore '**/*.test.ts' --ignore '**/__tests__/**'",
84
+ "build": "swc --delete-dir-on-start --strip-leading-paths --out-dir dist/ src",
81
85
  "build:types": "pkg-utils build --emitDeclarationOnly",
82
86
  "check:types": "tsc --noEmit",
83
87
  "lint": "eslint .",