@sanity/workbench-cli 2.0.2 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +1 -1
  2. package/dist/_exports/_internal_render.d.ts +12 -0
  3. package/dist/_exports/_internal_render.js +3 -0
  4. package/dist/_exports/_internal_render.js.map +1 -0
  5. package/dist/_exports/build.d.ts +4 -4
  6. package/dist/_exports/build.js +2 -1
  7. package/dist/_exports/build.js.map +1 -1
  8. package/dist/_exports/defineApp-DldjQwq6.d.ts +375 -0
  9. package/dist/_exports/deploy.d.ts +10 -9
  10. package/dist/_exports/deploy.js +1 -0
  11. package/dist/_exports/deploy.js.map +1 -1
  12. package/dist/_exports/dev.d.ts +1 -1
  13. package/dist/_exports/index.d.ts +23 -16
  14. package/dist/_exports/index.js +2 -1
  15. package/dist/_exports/index.js.map +1 -1
  16. package/dist/_exports/preview.d.ts +1 -1
  17. package/dist/_exports/{registry-DI7hnTof.d.ts → registry-HE_dEHFa.d.ts} +38 -15
  18. package/dist/_exports/resolveWorkbenchConfig-6iznHbED.d.ts +60 -0
  19. package/dist/_exports/{summarizeInterfaces-DBGiAwNT.d.ts → summarizeInterfaces-CjkeWwkY.d.ts} +20 -17
  20. package/dist/_exports/undeploy.d.ts +12 -9
  21. package/dist/actions/build/artifact.js +1 -1
  22. package/dist/actions/build/artifact.js.map +1 -1
  23. package/dist/actions/build/views/artifact.js +1 -1
  24. package/dist/actions/build/views/artifact.js.map +1 -1
  25. package/dist/actions/build/vite/optimize-deps.js +3 -3
  26. package/dist/actions/build/vite/optimize-deps.js.map +1 -1
  27. package/dist/actions/build/vite/plugins/plugin-module-federation.js +8 -17
  28. package/dist/actions/build/vite/plugins/plugin-module-federation.js.map +1 -1
  29. package/dist/actions/build/vite/plugins/plugin-sanity-federation-runtime.js +1 -1
  30. package/dist/actions/build/vite/plugins/plugin-sanity-federation-runtime.js.map +1 -1
  31. package/dist/actions/build/vite/workbench-vite-plugins.js +1 -1
  32. package/dist/actions/build/vite/workbench-vite-plugins.js.map +1 -1
  33. package/dist/actions/deploy/deployPayload.js +0 -3
  34. package/dist/actions/deploy/deployPayload.js.map +1 -1
  35. package/dist/actions/deploy/deployWorkbenchApp.js +46 -4
  36. package/dist/actions/deploy/deployWorkbenchApp.js.map +1 -1
  37. package/dist/actions/deploy/getWorkbench.js +4 -5
  38. package/dist/actions/deploy/getWorkbench.js.map +1 -1
  39. package/dist/actions/deploy/summarizeInterfaces.js +14 -10
  40. package/dist/actions/deploy/summarizeInterfaces.js.map +1 -1
  41. package/dist/actions/deploy/viewDeployment.js +17 -5
  42. package/dist/actions/deploy/viewDeployment.js.map +1 -1
  43. package/dist/actions/dev/deriveConfigs.js +9 -6
  44. package/dist/actions/dev/deriveConfigs.js.map +1 -1
  45. package/dist/actions/dev/exposesSetId.js +2 -2
  46. package/dist/actions/dev/exposesSetId.js.map +1 -1
  47. package/dist/actions/dev/registry.js +31 -25
  48. package/dist/actions/dev/registry.js.map +1 -1
  49. package/dist/actions/dev/startDevManifestWatcher.js.map +1 -1
  50. package/dist/actions/dev/startDevServerRegistration.js +35 -60
  51. package/dist/actions/dev/startDevServerRegistration.js.map +1 -1
  52. package/dist/actions/dev/startWorkbenchDevServer.js +15 -33
  53. package/dist/actions/dev/startWorkbenchDevServer.js.map +1 -1
  54. package/dist/actions/dev/writeWorkbenchRuntime.js +2 -2
  55. package/dist/actions/dev/writeWorkbenchRuntime.js.map +1 -1
  56. package/dist/actions/preview/serveBuiltApplication.js +1 -1
  57. package/dist/actions/preview/serveBuiltApplication.js.map +1 -1
  58. package/dist/actions/preview/startWorkbenchPreview.js +1 -1
  59. package/dist/actions/preview/startWorkbenchPreview.js.map +1 -1
  60. package/dist/actions/undeploy/workbenchUndeployAdapter.js +24 -33
  61. package/dist/actions/undeploy/workbenchUndeployAdapter.js.map +1 -1
  62. package/dist/appId.js +13 -9
  63. package/dist/appId.js.map +1 -1
  64. package/dist/applicationReference.js +12 -0
  65. package/dist/applicationReference.js.map +1 -0
  66. package/dist/contract.js +69 -31
  67. package/dist/contract.js.map +1 -1
  68. package/dist/defineApp.js +53 -63
  69. package/dist/defineApp.js.map +1 -1
  70. package/dist/defineView.js +3 -3
  71. package/dist/defineView.js.map +1 -1
  72. package/dist/deriveInterfaces.js +45 -19
  73. package/dist/deriveInterfaces.js.map +1 -1
  74. package/dist/renderDashboard.js +63 -0
  75. package/dist/renderDashboard.js.map +1 -0
  76. package/dist/resolveWorkbenchApp.js +13 -9
  77. package/dist/resolveWorkbenchApp.js.map +1 -1
  78. package/dist/resolveWorkbenchConfig.js +30 -0
  79. package/dist/resolveWorkbenchConfig.js.map +1 -0
  80. package/dist/services/applications.js +7 -1
  81. package/dist/services/applications.js.map +1 -1
  82. package/package.json +12 -6
  83. package/dist/_exports/contract-DyG11fQ7.d.ts +0 -45
  84. package/dist/_exports/defineApp-r_CmoZfS.d.ts +0 -169
  85. package/dist/_exports/resolveWorkbenchApp-DqFqET9E.d.ts +0 -41
package/dist/defineApp.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod/mini';
2
2
  import { APP_SLUG_PATTERN } from './appSlug.js';
3
- import { ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } from './contract.js';
3
+ import { DockSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } from './contract.js';
4
4
  /**
5
5
  * Dashboard visibility values. Mirrors `APP_VISIBILITIES` in `@sanity/cli-core`
6
6
  * (which can't be imported here — pulling the barrel into this lean module bloats
@@ -17,16 +17,10 @@ import { ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } fr
17
17
  'coreApp',
18
18
  'studio',
19
19
  'canvas',
20
- 'dashboard',
21
- 'media-library'
22
- ]);
23
- /** Dock groups an app can place itself into. */ const DockGroupSchema = z.enum([
24
- 'dock.system',
25
- 'dock.applications',
26
- 'dock.user'
20
+ 'dashboard'
27
21
  ]);
28
22
  /**
29
- * Runtime-validation schema for `unstable_defineApp`.
23
+ * Runtime-validation schema for `defineApplication`.
30
24
  * @internal
31
25
  */ export const DefineAppInputSchema = z.object({
32
26
  /**
@@ -34,31 +28,34 @@ import { ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema } fr
34
28
  * from the public `DefineAppInput` type.
35
29
  * @internal
36
30
  */ applicationType: z.optional(ApplicationType),
37
- /**
38
- * Deployed as a versioned snapshot on the app's org installation, not the
39
- * application service. Singletons only. Internal, so excluded from the public
40
- * `DefineAppInput` and set via `@ts-expect-error` like `applicationType`.
41
- * @internal
42
- */ config: z.optional(ConfigSchema),
31
+ /** Default placement inherited by panel and window views. */ dock: z.optional(DockSchema),
43
32
  /**
44
33
  * App entrypoint module. Defaults to `./src/App.tsx` when omitted. The build
45
34
  * derives the app's navigable `app` view from it. SDK apps only — setting it
46
35
  * on a studio is rejected (studio app views are not yet implemented).
47
36
  */ entry: z.optional(z.string("must be a path to the app's entry file")),
48
- /** Dock group to render in. Defaults to `dock.applications` when omitted. */ group: z.optional(DockGroupSchema),
49
37
  /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */ icon: z.optional(z.string()),
50
38
  /**
51
- * Sanity-owned app deployed once, installed per org; excluded from the public `DefineAppInput`.
52
- * @internal
53
- */ isSingleton: z.optional(z.boolean()),
54
- /** Organization that owns the app — the workbench runs and deploys against it. */ organizationId: z.string("App `organizationId` is required pass the owning organization's ID to `unstable_defineApp`"),
55
- /** Sort position within the group, ascending. Defaults to `100` when omitted. */ priority: z.optional(z.number()),
56
- /** Background services the app runs (e.g. a `worker` emitting dock badges). */ services: z.optional(z.array(ServiceDeclarationSchema, 'must be an array of services').check(z.refine((services)=>new Set(services.map((service)=>service.name)).size === services.length, 'Service `name` must be unique within an app'))),
39
+ * Stable identity, distinct from the `slug` address. Defaults to `slug` when
40
+ * omitted. Identity keys — the build id and derived interface ids — are built
41
+ * from this, so renaming the slug no longer changes identity.
42
+ */ name: z.optional(z.string().check(z.regex(APP_SLUG_PATTERN, 'App `name` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric'))),
43
+ /** Organization that owns the app the workbench runs and deploys against it. */ organizationId: z.string("App `organizationId` is required — pass the owning organization's ID to `defineApplication`"),
57
44
  slug: z.string('App `slug` is required — the hostname the application is created at on deploy').check(z.regex(APP_SLUG_PATTERN, 'App `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric')),
58
45
  /** User-facing app title. Wins over studio.config.ts title on merge. */ title: z.string(),
59
- /** Views the app exposes (e.g. dock panels). */ views: z.optional(z.array(InterfaceDeclarationSchema, 'must be an array of panels').check(z.refine((views)=>new Set(views.map((view)=>view.name)).size === views.length, 'View `name` must be unique within an app'))),
60
- /** Dashboard visibility of the app. Defaults to `default` when omitted. */ visibility: z.optional(z.enum(APP_VISIBILITIES))
61
- }).check(// Studio app views are not implemented yet. A studio that declares `entry`
46
+ /** Views the app exposes (e.g. a window, dock panels, and tiles). */ views: z.optional(z.array(InterfaceDeclarationSchema, 'must be an array of views')),
47
+ /** Dashboard visibility of the app. Defaults to `default` when omitted. */ visibility: z.optional(z.enum(APP_VISIBILITIES)),
48
+ /** Background web workers the app runs. */ webWorkers: z.optional(z.array(ServiceDeclarationSchema, 'must be an array of web workers'))
49
+ }).check(z.refine((input)=>{
50
+ const names = [
51
+ ...input.entry === undefined ? [] : [
52
+ input.name ?? input.slug
53
+ ],
54
+ ...(input.views ?? []).map((view)=>view.name),
55
+ ...(input.webWorkers ?? []).map((webWorker)=>webWorker.name)
56
+ ];
57
+ return new Set(names).size === names.length;
58
+ }, '`name` must be unique across views and web workers. Rename one of the duplicates.'), // Studio app views are not implemented yet. A studio that declares `entry`
62
59
  // (the SDK app-view entrypoint) is rejected here rather than silently
63
60
  // generating one; studios keep navigating via their existing render path.
64
61
  z.refine((input)=>!(input.applicationType === 'studio' && input.entry !== undefined), {
@@ -66,18 +63,7 @@ z.refine((input)=>!(input.applicationType === 'studio' && input.entry !== undefi
66
63
  path: [
67
64
  'entry'
68
65
  ]
69
- })).check(// An config belongs to a Sanity-owned singleton (the Media
70
- // Library). A non-singleton declaring one is rejected — see
71
- // {@link readConfig} for the runtime guard.
72
- z.refine((input)=>!(input.config && !input.isSingleton), {
73
- error: '`config` is only supported for singleton apps',
74
- path: [
75
- 'config'
76
- ]
77
- })).check(// A navigable app view (`entry`) and dock panels are the mutually-exclusive
78
- // navigable kinds. An `asset_source` view is a separate kind — a picker
79
- // brokered to other apps — so it may sit alongside either.
80
- z.refine((input)=>!(input.entry !== undefined && (input.views?.some((view)=>view.type === 'panel') ?? false)), 'An app cannot expose both an app view (`entry`) and panel views. Declare one or the other.')).check(z.refine((input)=>(input.views?.filter((view)=>view.type === 'panel').length ?? 0) <= 1, 'An app can expose at most one panel view.'));
66
+ }));
81
67
  /**
82
68
  * Nominal brand the CLI discriminates on to enable the workbench build/deploy
83
69
  * codepath. Registered via `Symbol.for` so the marker survives module-realm
@@ -85,31 +71,19 @@ z.refine((input)=>!(input.entry !== undefined && (input.views?.some((view)=>view
85
71
  * `Symbol.for` rather than importing it, so it stays internal to this module.
86
72
  */ const WORKBENCH_APP = Symbol.for('sanity.workbench.defineApp');
87
73
  /**
88
- * Whether `app` is a branded `unstable_defineApp(...)` result — the sole
74
+ * Whether `app` is a branded `defineApplication(...)` result — the sole
89
75
  * workbench opt-in.
90
76
  * @public
91
77
  */ export function isWorkbenchApp(app) {
92
78
  return typeof app === 'object' && app !== null && WORKBENCH_APP in app;
93
79
  }
94
- /**
95
- * The app's config, or `undefined` when it declares none. Throws
96
- * when a non-singleton declares one — configs belong to Sanity-owned singletons,
97
- * so build/dev/deploy all read it through here to reject the combination
98
- * consistently.
99
- * @internal
100
- */ export function readConfig(app) {
101
- if (app.config && !app.isSingleton) {
102
- throw new Error('`config` is only supported for singleton apps');
103
- }
104
- return app.config;
105
- }
106
80
  /**
107
81
  * Declare a Sanity Workbench application. Identity at runtime — returns the same
108
82
  * object reference, tagged with the workbench brand. Field validation (the
109
83
  * `slug` pattern etc.) runs at build time in the CLI via `DefineAppInputSchema`;
110
84
  * this helper stays a thin, pure identity wrapper.
111
85
  * @public
112
- */ export function unstable_defineApp(input) {
86
+ */ export function defineApplication(input) {
113
87
  return Object.defineProperty(input, WORKBENCH_APP, {
114
88
  configurable: false,
115
89
  enumerable: false,
@@ -118,20 +92,36 @@ z.refine((input)=>!(input.entry !== undefined && (input.views?.some((view)=>view
118
92
  });
119
93
  }
120
94
  /**
121
- * Declare the Sanity Media Library as a workbench app a singleton whose `fields` become its config.
95
+ * Nominal brand the CLI discriminates a config on. A config is *not* an app: it
96
+ * carries no `slug`/`title`/application identity, only a target `appType`, its
97
+ * owning `organizationId`, and its `fields`. Registered via `Symbol.for` so the
98
+ * marker survives module-realm boundaries — `@sanity/cli-core` re-derives the
99
+ * same global symbol rather than importing it.
100
+ */ const WORKBENCH_CONFIG = Symbol.for('sanity.workbench.defineConfig');
101
+ /**
102
+ * Whether `app` is a branded `unstable_defineMediaLibrary(...)` config — a
103
+ * config-carrier rather than an app. Configs live in `cliConfig.app` alongside
104
+ * apps but resolve through `resolveWorkbenchConfig`, not `resolveWorkbenchApp`.
105
+ * @public
106
+ */ export function isWorkbenchConfig(app) {
107
+ return typeof app === 'object' && app !== null && WORKBENCH_CONFIG in app;
108
+ }
109
+ /**
110
+ * Declare the Sanity Media Library config. The Media Library is a Sanity-owned
111
+ * singleton, so this is not an app — it carries no slug or title, only the
112
+ * target `appType`, its owning organization, and the `fields` it contributes to
113
+ * the installation's config.
122
114
  * @public
123
115
  */ export function unstable_defineMediaLibrary(input) {
124
- return unstable_defineApp({
125
- // @ts-expect-error -- `applicationType`/`isSingleton`/`config` are internal, excluded from `DefineAppInput`; Sanity-owned apps set them
126
- applicationType: 'media-library',
127
- config: input.fields?.length ? {
128
- appType: 'media-library',
129
- fields: input.fields
130
- } : undefined,
131
- isSingleton: true,
132
- organizationId: input.organizationId,
133
- slug: 'media-library',
134
- title: 'Media Library'
116
+ return Object.defineProperty({
117
+ appType: 'media-library',
118
+ fields: input.fields ?? [],
119
+ organizationId: input.organizationId
120
+ }, WORKBENCH_CONFIG, {
121
+ configurable: false,
122
+ enumerable: false,
123
+ value: true,
124
+ writable: false
135
125
  });
136
126
  }
137
127
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {APP_SLUG_PATTERN} from './appSlug.js'\nimport {ConfigSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\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`.\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(\"must be a path to the app's entry file\")),\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 /** 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 /** Background services the app runs (e.g. a `worker` emitting dock badges). */\n services: z.optional(\n z\n .array(ServiceDeclarationSchema, 'must be an array of services')\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\n .string('App `slug` is required — the hostname the application is created at on deploy')\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /** Views the app exposes (e.g. dock panels). */\n views: z.optional(\n z\n .array(InterfaceDeclarationSchema, 'must be an array of panels')\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 .check(\n // A navigable app view (`entry`) and dock panels are the mutually-exclusive\n // navigable kinds. An `asset_source` view is a separate kind — a picker\n // brokered to other apps — so it may sit alongside either.\n z.refine(\n (input) =>\n !(\n input.entry !== undefined &&\n (input.views?.some((view) => view.type === 'panel') ?? false)\n ),\n 'An app cannot expose both an app view (`entry`) and panel views. Declare one or the other.',\n ),\n )\n .check(\n z.refine(\n (input) => (input.views?.filter((view) => view.type === 'panel').length ?? 0) <= 1,\n 'An app can expose at most one panel view.',\n ),\n )\n\n/** The `asset_source` variant of an app's `views`. @public */\nexport type AssetSourceView = Extract<\n NonNullable<z.output<typeof DefineAppInputSchema>['views']>[number],\n {type: 'asset_source'}\n>\n\n/** The `tile` variant of an app's `views`. @public */\nexport type TileView = Extract<\n NonNullable<z.output<typeof DefineAppInputSchema>['views']>[number],\n {type: 'tile'}\n>\n\n/**\n * User-facing input for `unstable_defineApp`. Excludes the internal\n * `applicationType`, `isSingleton`, and `config` — validated by the schema but\n * not part of the public surface (Sanity-owned apps set them via\n * `@ts-expect-error`). A union: an app declares an app `entry` (navigable) or\n * panel `views`, never both — but `asset_source` and `tile` views are separate\n * kinds and may accompany either.\n * @public\n */\nexport type DefineAppInput = Omit<\n z.output<typeof DefineAppInputSchema>,\n 'applicationType' | 'config' | 'entry' | 'isSingleton' | 'views'\n> &\n (\n | {entry?: never; views?: NonNullable<z.output<typeof DefineAppInputSchema>['views']>}\n | {entry?: string; views?: (AssetSourceView | TileView)[]}\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 type DefineAppResult = DefineAppInput & {readonly [WORKBENCH_APP]: true}\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 * `slug` 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 organizationId: input.organizationId,\n slug: 'media-library',\n title: 'Media Library',\n })\n}\n"],"names":["z","APP_SLUG_PATTERN","ConfigSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_VISIBILITIES","ApplicationType","enum","DockGroupSchema","DefineAppInputSchema","object","applicationType","optional","config","entry","string","group","icon","isSingleton","boolean","organizationId","priority","number","services","array","check","refine","Set","map","service","name","size","length","slug","regex","title","views","view","visibility","input","undefined","error","path","some","type","filter","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","readConfig","Error","unstable_defineApp","Object","defineProperty","configurable","enumerable","value","writable","unstable_defineMediaLibrary","fields","appType"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,SAAQC,gBAAgB,QAAO,eAAc;AAC7C,SAAQC,YAAY,EAAEC,0BAA0B,EAAEC,wBAAwB,QAAO,gBAAe;AAEhG;;;;CAIC,GACD,MAAMC,mBAAmB;IAAC;IAAW;IAAY;CAAW;AAE5D;;;CAGC,GACD,MAAMC,kBAAkBN,EAAEO,IAAI,CAAC;IAAC;IAAW;IAAU;IAAU;IAAa;CAAgB;AAE5F,8CAA8C,GAC9C,MAAMC,kBAAkBR,EAAEO,IAAI,CAAC;IAAC;IAAe;IAAqB;CAAY;AAUhF;;;CAGC,GACD,OAAO,MAAME,uBAAuBT,EACjCU,MAAM,CAAC;IACN;;;;KAIC,GACDC,iBAAiBX,EAAEY,QAAQ,CAACN;IAC5B;;;;;KAKC,GACDO,QAAQb,EAAEY,QAAQ,CAACV;IACnB;;;;KAIC,GACDY,OAAOd,EAAEY,QAAQ,CAACZ,EAAEe,MAAM,CAAC;IAC3B,2EAA2E,GAC3EC,OAAOhB,EAAEY,QAAQ,CAACJ;IAClB,6EAA6E,GAC7ES,MAAMjB,EAAEY,QAAQ,CAACZ,EAAEe,MAAM;IACzB;;;KAGC,GACDG,aAAalB,EAAEY,QAAQ,CAACZ,EAAEmB,OAAO;IACjC,gFAAgF,GAChFC,gBAAgBpB,EAAEe,MAAM,CACtB;IAEF,+EAA+E,GAC/EM,UAAUrB,EAAEY,QAAQ,CAACZ,EAAEsB,MAAM;IAC7B,6EAA6E,GAC7EC,UAAUvB,EAAEY,QAAQ,CAClBZ,EACGwB,KAAK,CAACpB,0BAA0B,gCAChCqB,KAAK,CACJzB,EAAE0B,MAAM,CACN,CAACH,WAAa,IAAII,IAAIJ,SAASK,GAAG,CAAC,CAACC,UAAYA,QAAQC,IAAI,GAAGC,IAAI,KAAKR,SAASS,MAAM,EACvF;IAIRC,MAAMjC,EACHe,MAAM,CAAC,iFACPU,KAAK,CACJzB,EAAEkC,KAAK,CACLjC,kBACA;IAGN,sEAAsE,GACtEkC,OAAOnC,EAAEe,MAAM;IACf,8CAA8C,GAC9CqB,OAAOpC,EAAEY,QAAQ,CACfZ,EACGwB,KAAK,CAACrB,4BAA4B,8BAClCsB,KAAK,CACJzB,EAAE0B,MAAM,CACN,CAACU,QAAU,IAAIT,IAAIS,MAAMR,GAAG,CAAC,CAACS,OAASA,KAAKP,IAAI,GAAGC,IAAI,KAAKK,MAAMJ,MAAM,EACxE;IAIR,yEAAyE,GACzEM,YAAYtC,EAAEY,QAAQ,CAACZ,EAAEO,IAAI,CAACF;AAChC,GACCoB,KAAK,CACJ,2EAA2E;AAC3E,sEAAsE;AACtE,0EAA0E;AAC1EzB,EAAE0B,MAAM,CAAC,CAACa,QAAU,CAAEA,CAAAA,MAAM5B,eAAe,KAAK,YAAY4B,MAAMzB,KAAK,KAAK0B,SAAQ,GAAI;IACtFC,OAAO;IACPC,MAAM;QAAC;KAAQ;AACjB,IAEDjB,KAAK,CACJ,2DAA2D;AAC3D,4DAA4D;AAC5D,4CAA4C;AAC5CzB,EAAE0B,MAAM,CAAC,CAACa,QAAU,CAAEA,CAAAA,MAAM1B,MAAM,IAAI,CAAC0B,MAAMrB,WAAW,AAAD,GAAI;IACzDuB,OAAO;IACPC,MAAM;QAAC;KAAS;AAClB,IAEDjB,KAAK,CACJ,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3DzB,EAAE0B,MAAM,CACN,CAACa,QACC,CACEA,CAAAA,MAAMzB,KAAK,KAAK0B,aACfD,CAAAA,MAAMH,KAAK,EAAEO,KAAK,CAACN,OAASA,KAAKO,IAAI,KAAK,YAAY,KAAI,CAAC,GAEhE,+FAGHnB,KAAK,CACJzB,EAAE0B,MAAM,CACN,CAACa,QAAU,AAACA,CAAAA,MAAMH,KAAK,EAAES,OAAO,CAACR,OAASA,KAAKO,IAAI,KAAK,SAASZ,UAAU,CAAA,KAAM,GACjF,8CAEH;AAgCH;;;;;CAKC,GACD,MAAMc,gBAA+BC,OAAOC,GAAG,CAAC;AAiBhD;;;;CAIC,GACD,OAAO,SAASC,eAAeC,GAAY;IACzC,OAAO,OAAOA,QAAQ,YAAYA,QAAQ,QAAQJ,iBAAiBI;AACrE;AAEA;;;;;;CAMC,GACD,OAAO,SAASC,WAAWD,GAAiB;IAC1C,IAAIA,IAAIrC,MAAM,IAAI,CAACqC,IAAIhC,WAAW,EAAE;QAClC,MAAM,IAAIkC,MAAM;IAClB;IACA,OAAOF,IAAIrC,MAAM;AACnB;AAEA;;;;;;CAMC,GACD,OAAO,SAASwC,mBAAmBd,KAAqB;IACtD,OAAOe,OAAOC,cAAc,CAAChB,OAAOO,eAAe;QACjDU,cAAc;QACdC,YAAY;QACZC,OAAO;QACPC,UAAU;IACZ;AACF;AA2BA;;;CAGC,GACD,OAAO,SAASC,4BAA4BrB,KAA8B;IACxE,OAAOc,mBAAmB;QACxB,wIAAwI;QACxI1C,iBAAiB;QACjBE,QAAQ0B,MAAMsB,MAAM,EAAE7B,SAAS;YAAC8B,SAAS;YAAiBD,QAAQtB,MAAMsB,MAAM;QAAA,IAAIrB;QAClFtB,aAAa;QACbE,gBAAgBmB,MAAMnB,cAAc;QACpCa,MAAM;QACNE,OAAO;IACT;AACF"}
1
+ {"version":3,"sources":["../src/defineApp.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nimport {APP_SLUG_PATTERN} from './appSlug.js'\nimport {DockSchema, InterfaceDeclarationSchema, ServiceDeclarationSchema} from './contract.js'\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'])\n\n/**\n * Runtime-validation schema for `defineApplication`.\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 /** Default placement inherited by panel and window views. */\n dock: z.optional(DockSchema),\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(\"must be a path to the app's entry file\")),\n /** Optional icon override (path to an SVG). Wins over manifest/studio icon. */\n icon: z.optional(z.string()),\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug` when\n * omitted. Identity keys — the build id and derived interface ids — are built\n * from this, so renaming the slug no longer changes identity.\n */\n name: z.optional(\n z\n .string()\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `name` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n ),\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 `defineApplication`\",\n ),\n slug: z\n .string('App `slug` is required — the hostname the application is created at on deploy')\n .check(\n z.regex(\n APP_SLUG_PATTERN,\n 'App `slug` must be lowercase alphanumerics and hyphens, starting with a letter and ending with an alphanumeric',\n ),\n ),\n /** User-facing app title. Wins over studio.config.ts title on merge. */\n title: z.string(),\n /** Views the app exposes (e.g. a window, dock panels, and tiles). */\n views: z.optional(z.array(InterfaceDeclarationSchema, 'must be an array of views')),\n /** Dashboard visibility of the app. Defaults to `default` when omitted. */\n visibility: z.optional(z.enum(APP_VISIBILITIES)),\n /** Background web workers the app runs. */\n webWorkers: z.optional(z.array(ServiceDeclarationSchema, 'must be an array of web workers')),\n })\n .check(\n z.refine((input) => {\n const names = [\n ...(input.entry === undefined ? [] : [input.name ?? input.slug]),\n ...(input.views ?? []).map((view) => view.name),\n ...(input.webWorkers ?? []).map((webWorker) => webWorker.name),\n ]\n return new Set(names).size === names.length\n }, '`name` must be unique across views and web workers. Rename one of the duplicates.'),\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\n/**\n * User-facing input for `defineApplication`. Excludes the internal\n * `applicationType`.\n * @public\n */\nexport type DefineAppInput = Omit<z.output<typeof DefineAppInputSchema>, 'applicationType'>\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 `defineApplication`. Carries the same fields as the\n * input plus the internal brand — users only ever see `DefineAppInput`.\n * @public\n */\nexport type DefineAppResult = DefineAppInput & {readonly [WORKBENCH_APP]: true}\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 `defineApplication(...)` 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 * Declare a Sanity Workbench application. Identity at runtime — returns the same\n * object reference, tagged with the workbench brand. Field validation (the\n * `slug` 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 defineApplication(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 * Nominal brand the CLI discriminates a config on. A config is *not* an app: it\n * carries no `slug`/`title`/application identity, only a target `appType`, its\n * owning `organizationId`, and its `fields`. Registered via `Symbol.for` so the\n * marker survives module-realm boundaries — `@sanity/cli-core` re-derives the\n * same global symbol rather than importing it.\n */\nconst WORKBENCH_CONFIG: unique symbol = Symbol.for('sanity.workbench.defineConfig')\n\n/**\n * A branded workbench config as the CLI reads it: bound to its target app by\n * `appType`, not carrying its own app identity. The deploy/undeploy/build paths\n * discriminate it via {@link isWorkbenchConfig}.\n * @public\n */\nexport interface WorkbenchConfig {\n appType: 'media-library'\n fields: MediaLibraryField[]\n organizationId: string\n readonly [WORKBENCH_CONFIG]: true\n}\n\n/**\n * Whether `app` is a branded `unstable_defineMediaLibrary(...)` config — a\n * config-carrier rather than an app. Configs live in `cliConfig.app` alongside\n * apps but resolve through `resolveWorkbenchConfig`, not `resolveWorkbenchApp`.\n * @public\n */\nexport function isWorkbenchConfig(app: unknown): app is WorkbenchConfig {\n return typeof app === 'object' && app !== null && WORKBENCH_CONFIG in app\n}\n\n/**\n * Declare the Sanity Media Library config. The Media Library is a Sanity-owned\n * singleton, so this is not an app — it carries no slug or title, only the\n * target `appType`, its owning organization, and the `fields` it contributes to\n * the installation's config.\n * @public\n */\nexport function unstable_defineMediaLibrary(input: DefineMediaLibraryInput): WorkbenchConfig {\n return Object.defineProperty(\n {appType: 'media-library', fields: input.fields ?? [], organizationId: input.organizationId},\n WORKBENCH_CONFIG,\n {configurable: false, enumerable: false, value: true, writable: false},\n ) as WorkbenchConfig\n}\n"],"names":["z","APP_SLUG_PATTERN","DockSchema","InterfaceDeclarationSchema","ServiceDeclarationSchema","APP_VISIBILITIES","ApplicationType","enum","DefineAppInputSchema","object","applicationType","optional","dock","entry","string","icon","name","check","regex","organizationId","slug","title","views","array","visibility","webWorkers","refine","input","names","undefined","map","view","webWorker","Set","size","length","error","path","WORKBENCH_APP","Symbol","for","isWorkbenchApp","app","defineApplication","Object","defineProperty","configurable","enumerable","value","writable","WORKBENCH_CONFIG","isWorkbenchConfig","unstable_defineMediaLibrary","appType","fields"],"mappings":"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"}
@@ -4,14 +4,14 @@ import { VIEW_CONTRACT_VERSION } from './contract.js';
4
4
  * and the props each component receives — `"panel"` yields a `{title, panel}`
5
5
  * record whose components are typed with the panel props.
6
6
  *
7
- * Returns the component(s) tagged with their type and the contract version, for
7
+ * Returns the component(s) tagged with their surface and contract version, for
8
8
  * the CLI build to generate render artifacts from. Used as the default export of
9
9
  * a view's `src` file.
10
10
  * @public
11
- */ export function unstable_defineView(type, components) {
11
+ */ export function unstable_defineView(surface, components) {
12
12
  return {
13
13
  components,
14
- type,
14
+ surface,
15
15
  version: VIEW_CONTRACT_VERSION
16
16
  };
17
17
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defineView.ts"],"sourcesContent":["import {type AssetSourceComponentProps} from '@sanity/types'\n\nimport {\n type InterfaceType,\n type TileSize,\n VIEW_CONTRACT_VERSION,\n type ViewComponent,\n type ViewComponentBaseProps,\n} from './contract.js'\n\n/**\n * Props a panel component receives: its interface record, minus the\n * service-assigned `id`/`deployment_id` a local dev server can't provide. Mirrors\n * the `panel` record the workbench host renders from (the wire format owned by\n * `@sanity/workbench`); drift is guarded by the stamped contract version.\n * @public\n */\nexport type PanelViewProps = ViewComponentBaseProps<{\n name: string\n src: string\n title: string\n type: 'panel'\n}>\n\n/**\n * The component slots a `panel` view exposes — each its own module-federation\n * island, typed with the panel props.\n * @public\n */\nexport interface PanelViewComponents {\n panel: ViewComponent<PanelViewProps>\n title: ViewComponent<PanelViewProps>\n}\n\n/**\n * A panel's view-component slot — the module-federation expose for one island.\n * @public\n */\nexport type PanelComponent = keyof PanelViewComponents\n\n/**\n * The component slots an `asset_source` view exposes — a single picker island,\n * typed with the studio asset-source props it renders behind. The props are\n * `@sanity/types`' `AssetSourceComponentProps` directly, so an authored picker\n * receives exactly what a studio `AssetSource.component` does.\n * @public\n */\nexport interface AssetSourceViewComponents {\n asset_source: ViewComponent<AssetSourceComponentProps>\n}\n\n/**\n * An asset source's view-component slot — the module-federation expose for its\n * one island.\n * @public\n */\nexport type AssetSourceComponent = keyof AssetSourceViewComponents\n\n/**\n * Props a tile component receives: its own interface record (name/src/title/\n * type) plus its footprint `size`, so it can render per family. Mirrors the\n * `tile` record the dashboard host renders from; drift is guarded by the stamped\n * contract version. Placement `priority` is host-only metadata, not surfaced here.\n * @public\n */\nexport type TileViewProps = ViewComponentBaseProps<{\n name: string\n size: TileSize\n src: string\n title: string\n type: 'tile'\n}>\n\n/**\n * The component slot a `tile` view exposes — a single island, typed with the\n * tile props.\n * @public\n */\nexport interface TileViewComponents {\n tile: ViewComponent<TileViewProps>\n}\n\n/**\n * A tile's view-component slot — the module-federation expose for its one island.\n * @public\n */\nexport type TileComponent = keyof TileViewComponents\n\n/**\n * The components each interface type exposes, keyed by type.\n * @public\n */\nexport interface ViewComponentsByType {\n asset_source: AssetSourceViewComponents\n panel: PanelViewComponents\n tile: TileViewComponents\n}\n\n/**\n * The result of `unstable_defineView`: the author's component(s), the view type,\n * and the internal contract version the build artifact targets.\n * @public\n */\nexport interface DefinedView<TType extends InterfaceType = InterfaceType> {\n readonly components: ViewComponentsByType[TType]\n readonly type: TType\n /** @internal */\n readonly version: typeof VIEW_CONTRACT_VERSION\n}\n\n/**\n * Define a Sanity Workbench view. The first argument narrows the component shape\n * and the props each component receives — `\"panel\"` yields a `{title, panel}`\n * record whose components are typed with the panel props.\n *\n * Returns the component(s) tagged with their type and the contract version, for\n * the CLI build to generate render artifacts from. Used as the default export of\n * a view's `src` file.\n * @public\n */\nexport function unstable_defineView<TType extends InterfaceType>(\n type: TType,\n components: ViewComponentsByType[TType],\n): DefinedView<TType> {\n return {components, type, version: VIEW_CONTRACT_VERSION}\n}\n"],"names":["VIEW_CONTRACT_VERSION","unstable_defineView","type","components","version"],"mappings":"AAEA,SAGEA,qBAAqB,QAGhB,gBAAe;AAsGtB;;;;;;;;;CASC,GACD,OAAO,SAASC,oBACdC,IAAW,EACXC,UAAuC;IAEvC,OAAO;QAACA;QAAYD;QAAME,SAASJ;IAAqB;AAC1D"}
1
+ {"version":3,"sources":["../src/defineView.ts"],"sourcesContent":["import {type AssetSourceComponentProps} from '@sanity/types'\n\nimport {\n type TileSize,\n VIEW_CONTRACT_VERSION,\n type ViewComponent,\n type ViewComponentBaseProps,\n type ViewSurface,\n} from './contract.js'\n\n/** @public */\nexport type WindowViewProps = ViewComponentBaseProps<{\n name: string\n src: string\n surface: 'app'\n title: string\n}>\n\n/**\n * Props a panel component receives: its interface record, minus the\n * service-assigned `id`/`deployment_id` a local dev server can't provide. Mirrors\n * the `panel` record the workbench host renders from (the wire format owned by\n * `@sanity/workbench`); drift is guarded by the stamped contract version.\n * @public\n */\nexport type PanelViewProps = ViewComponentBaseProps<{\n name: string\n src: string\n surface: 'panel'\n title: string\n}>\n\n/**\n * The component slots a `panel` view exposes — each its own module-federation\n * island, typed with the panel props.\n * @public\n */\nexport interface PanelViewComponents {\n panel: ViewComponent<PanelViewProps>\n title: ViewComponent<PanelViewProps>\n}\n\n/**\n * A panel's view-component slot — the module-federation expose for one island.\n * @public\n */\nexport type PanelComponent = keyof PanelViewComponents\n\n/**\n * The component slots an `asset_source` view exposes — a single picker island,\n * typed with the studio asset-source props it renders behind. The props are\n * `@sanity/types`' `AssetSourceComponentProps` directly, so an authored picker\n * receives exactly what a studio `AssetSource.component` does.\n * @public\n */\nexport interface AssetSourceViewComponents {\n asset_source: ViewComponent<AssetSourceComponentProps>\n}\n\n/**\n * An asset source's view-component slot — the module-federation expose for its\n * one island.\n * @public\n */\nexport type AssetSourceComponent = keyof AssetSourceViewComponents\n\n/**\n * Props a tile component receives: its own interface record plus its footprint\n * `size`, so it can render per family. Mirrors the\n * `tile` record the dashboard host renders from; drift is guarded by the stamped\n * contract version. Placement `order` is host-only metadata, not surfaced here.\n * @public\n */\nexport type TileViewProps = ViewComponentBaseProps<{\n name: string\n size: TileSize\n src: string\n surface: 'tile'\n title: string\n}>\n\n/**\n * The component slot a `tile` view exposes — a single island, typed with the\n * tile props.\n * @public\n */\nexport interface TileViewComponents {\n tile: ViewComponent<TileViewProps>\n}\n\n/**\n * A tile's view-component slot — the module-federation expose for its one island.\n * @public\n */\nexport type TileComponent = keyof TileViewComponents\n\n/**\n * The components each view surface exposes.\n * @public\n */\nexport interface ViewComponentsBySurface {\n app: ViewComponent<WindowViewProps>\n asset_source: AssetSourceViewComponents\n panel: PanelViewComponents\n tile: TileViewComponents\n}\n\n/**\n * The result of `unstable_defineView`: the author's component(s), the view surface,\n * and the internal contract version the build artifact targets.\n * @public\n */\nexport interface DefinedView<TSurface extends ViewSurface = ViewSurface> {\n readonly components: ViewComponentsBySurface[TSurface]\n readonly surface: TSurface\n /** @internal */\n readonly version: typeof VIEW_CONTRACT_VERSION\n}\n\n/**\n * Define a Sanity Workbench view. The first argument narrows the component shape\n * and the props each component receives — `\"panel\"` yields a `{title, panel}`\n * record whose components are typed with the panel props.\n *\n * Returns the component(s) tagged with their surface and contract version, for\n * the CLI build to generate render artifacts from. Used as the default export of\n * a view's `src` file.\n * @public\n */\nexport function unstable_defineView<TSurface extends ViewSurface>(\n surface: TSurface,\n components: ViewComponentsBySurface[TSurface],\n): DefinedView<TSurface> {\n return {components, surface, version: VIEW_CONTRACT_VERSION}\n}\n"],"names":["VIEW_CONTRACT_VERSION","unstable_defineView","surface","components","version"],"mappings":"AAEA,SAEEA,qBAAqB,QAIhB,gBAAe;AA+GtB;;;;;;;;;CASC,GACD,OAAO,SAASC,oBACdC,OAAiB,EACjBC,UAA6C;IAE7C,OAAO;QAACA;QAAYD;QAASE,SAASJ;IAAqB;AAC7D"}
@@ -14,47 +14,73 @@ import { isWorkbenchApp } from './defineApp.js';
14
14
  throw new Error('App views for studios are not implemented yet');
15
15
  }
16
16
  const entry = isApp ? app.entry : GENERATED_ENTRY;
17
- const shared = (type, declaration)=>({
18
- id: `${app.slug}-${type}-${declaration.name}`,
19
- moduleId: interfaceModuleId(type, declaration.name),
17
+ // Identity, not address: interface ids and the app-view name key on `name`
18
+ // (which defaults to `slug`, so existing apps derive byte-identical ids).
19
+ const appName = app.name ?? app.slug;
20
+ const shared = (kind, declaration)=>({
21
+ id: `${appName}-${kind}-${declaration.name}`,
22
+ moduleId: interfaceModuleId(kind, declaration.name),
20
23
  name: declaration.name,
21
24
  src: declaration.src,
22
25
  title: declaration.title,
23
- type,
24
- version: interfaceContractVersion(type)
26
+ version: interfaceContractVersion(kind)
25
27
  });
28
+ const placementMetadata = (dock)=>{
29
+ const group = dock?.group ?? app.dock?.group;
30
+ const order = dock?.order ?? app.dock?.order;
31
+ if (group === undefined && order === undefined) return null;
32
+ return {
33
+ dock: {
34
+ ...group === undefined ? {} : {
35
+ group
36
+ },
37
+ ...order === undefined ? {} : {
38
+ order
39
+ }
40
+ }
41
+ };
42
+ };
26
43
  return [
27
44
  ...(app.views ?? []).map((view)=>{
28
- // Tile is the only view type with interface metadata: its footprint `size`
29
- // (required) and an optional sort `priority`. Both authored top-level.
30
- if (view.type === 'tile') {
45
+ if (view.surface === 'tile') {
31
46
  return {
32
- ...shared(view.type, view),
33
- metadata: view.priority === undefined ? {
47
+ ...shared(view.surface, view),
48
+ metadata: view.order === undefined ? {
34
49
  size: view.size
35
50
  } : {
36
- priority: view.priority,
51
+ order: view.order,
37
52
  size: view.size
38
- }
53
+ },
54
+ surface: view.surface
55
+ };
56
+ }
57
+ if (view.surface === 'app' || view.surface === 'panel') {
58
+ return {
59
+ ...shared(view.surface, view),
60
+ metadata: placementMetadata(view.dock),
61
+ surface: view.surface
39
62
  };
40
63
  }
41
64
  return {
42
- ...shared(view.type, view),
43
- metadata: null
65
+ ...shared(view.surface, view),
66
+ metadata: null,
67
+ surface: view.surface
44
68
  };
45
69
  }),
46
- ...(app.services ?? []).map((service)=>({
47
- ...shared('worker', service),
48
- metadata: null
70
+ ...(app.webWorkers ?? []).map((webWorker)=>({
71
+ ...shared('worker', webWorker),
72
+ metadata: null,
73
+ type: 'worker'
49
74
  })),
50
75
  ...entry === undefined ? [] : [
51
76
  {
52
77
  ...shared('app', {
53
- name: app.slug,
78
+ name: appName,
54
79
  src: entry,
55
80
  title: appTitle ?? app.title
56
81
  }),
57
- metadata: null
82
+ metadata: placementMetadata(),
83
+ surface: 'app'
58
84
  }
59
85
  ]
60
86
  ];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/deriveInterfaces.ts"],"sourcesContent":["import {type CliConfig} from '@sanity/cli-core'\n\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from './actions/build/vite/constants.js'\nimport {\n type AppInterfaceMetadata,\n interfaceContractVersion,\n type InterfaceKind,\n interfaceModuleId,\n type TileInterfaceMetadata,\n} from './contract.js'\nimport {isWorkbenchApp} from './defineApp.js'\n\n/** What a studio exposes as `./App` — the generated entry that renders `sanity.config.ts`. */\nconst GENERATED_ENTRY = `./${RUNTIME_DIR}/${FEDERATION_FILE_NAME}.jsx`\n\ninterface DerivedInterfaceBase {\n /** CLI-minted for a local interface; a deployed one gets its id from Brett. */\n id: string\n moduleId: string\n name: string\n src: string\n title: string\n\n version?: string\n}\n\n/** @internal */\nexport type DerivedInterface =\n | (DerivedInterfaceBase & {metadata: AppInterfaceMetadata | null; type: 'app'})\n | (DerivedInterfaceBase & {metadata: null; type: 'asset_source'})\n | (DerivedInterfaceBase & {metadata: null; type: 'panel'})\n | (DerivedInterfaceBase & {metadata: null; type: 'worker'})\n | (DerivedInterfaceBase & {metadata: TileInterfaceMetadata; type: 'tile'})\n\n/**\n * `appTitle` titles the app view where a deploy resolved one through `--title`;\n * dev takes it from the config.\n * @internal\n */\nexport function deriveInterfaces(\n app: CliConfig['app'],\n {appTitle, isApp}: {appTitle?: string; isApp: boolean},\n): DerivedInterface[] {\n if (!isWorkbenchApp(app)) return []\n\n // The schema rejects a *declared* studio with an `entry`; `isApp` is resolved\n // from the project, so a detected one only fails here.\n if (!isApp && app.entry !== undefined) {\n throw new Error('App views for studios are not implemented yet')\n }\n const entry = isApp ? app.entry : GENERATED_ENTRY\n\n const shared = <T extends InterfaceKind>(\n type: T,\n declaration: {name: string; src: string; title: string},\n ) => ({\n id: `${app.slug}-${type}-${declaration.name}`,\n moduleId: interfaceModuleId(type, declaration.name),\n name: declaration.name,\n src: declaration.src,\n title: declaration.title,\n type,\n version: interfaceContractVersion(type),\n })\n\n return [\n ...(app.views ?? []).map((view): DerivedInterface => {\n // Tile is the only view type with interface metadata: its footprint `size`\n // (required) and an optional sort `priority`. Both authored top-level.\n if (view.type === 'tile') {\n return {\n ...shared(view.type, view),\n metadata:\n view.priority === undefined\n ? {size: view.size}\n : {priority: view.priority, size: view.size},\n }\n }\n return {...shared(view.type, view), metadata: null}\n }),\n ...(app.services ?? []).map(\n (service): DerivedInterface => ({...shared('worker', service), metadata: null}),\n ),\n ...(entry === undefined\n ? []\n : [\n {\n ...shared('app', {name: app.slug, src: entry, title: appTitle ?? app.title}),\n metadata: null,\n },\n ]),\n ]\n}\n"],"names":["FEDERATION_FILE_NAME","RUNTIME_DIR","interfaceContractVersion","interfaceModuleId","isWorkbenchApp","GENERATED_ENTRY","deriveInterfaces","app","appTitle","isApp","entry","undefined","Error","shared","type","declaration","id","slug","name","moduleId","src","title","version","views","map","view","metadata","priority","size","services","service"],"mappings":"AAEA,SAAQA,oBAAoB,EAAEC,WAAW,QAAO,oCAAmC;AACnF,SAEEC,wBAAwB,EAExBC,iBAAiB,QAEZ,gBAAe;AACtB,SAAQC,cAAc,QAAO,iBAAgB;AAE7C,4FAA4F,GAC5F,MAAMC,kBAAkB,CAAC,EAAE,EAAEJ,YAAY,CAAC,EAAED,qBAAqB,IAAI,CAAC;AAqBtE;;;;CAIC,GACD,OAAO,SAASM,iBACdC,GAAqB,EACrB,EAACC,QAAQ,EAAEC,KAAK,EAAsC;IAEtD,IAAI,CAACL,eAAeG,MAAM,OAAO,EAAE;IAEnC,8EAA8E;IAC9E,uDAAuD;IACvD,IAAI,CAACE,SAASF,IAAIG,KAAK,KAAKC,WAAW;QACrC,MAAM,IAAIC,MAAM;IAClB;IACA,MAAMF,QAAQD,QAAQF,IAAIG,KAAK,GAAGL;IAElC,MAAMQ,SAAS,CACbC,MACAC,cACI,CAAA;YACJC,IAAI,GAAGT,IAAIU,IAAI,CAAC,CAAC,EAAEH,KAAK,CAAC,EAAEC,YAAYG,IAAI,EAAE;YAC7CC,UAAUhB,kBAAkBW,MAAMC,YAAYG,IAAI;YAClDA,MAAMH,YAAYG,IAAI;YACtBE,KAAKL,YAAYK,GAAG;YACpBC,OAAON,YAAYM,KAAK;YACxBP;YACAQ,SAASpB,yBAAyBY;QACpC,CAAA;IAEA,OAAO;WACF,AAACP,CAAAA,IAAIgB,KAAK,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC;YACxB,2EAA2E;YAC3E,uEAAuE;YACvE,IAAIA,KAAKX,IAAI,KAAK,QAAQ;gBACxB,OAAO;oBACL,GAAGD,OAAOY,KAAKX,IAAI,EAAEW,KAAK;oBAC1BC,UACED,KAAKE,QAAQ,KAAKhB,YACd;wBAACiB,MAAMH,KAAKG,IAAI;oBAAA,IAChB;wBAACD,UAAUF,KAAKE,QAAQ;wBAAEC,MAAMH,KAAKG,IAAI;oBAAA;gBACjD;YACF;YACA,OAAO;gBAAC,GAAGf,OAAOY,KAAKX,IAAI,EAAEW,KAAK;gBAAEC,UAAU;YAAI;QACpD;WACG,AAACnB,CAAAA,IAAIsB,QAAQ,IAAI,EAAE,AAAD,EAAGL,GAAG,CACzB,CAACM,UAA+B,CAAA;gBAAC,GAAGjB,OAAO,UAAUiB,QAAQ;gBAAEJ,UAAU;YAAI,CAAA;WAE3EhB,UAAUC,YACV,EAAE,GACF;YACE;gBACE,GAAGE,OAAO,OAAO;oBAACK,MAAMX,IAAIU,IAAI;oBAAEG,KAAKV;oBAAOW,OAAOb,YAAYD,IAAIc,KAAK;gBAAA,EAAE;gBAC5EK,UAAU;YACZ;SACD;KACN;AACH"}
1
+ {"version":3,"sources":["../src/deriveInterfaces.ts"],"sourcesContent":["import {type CliConfig} from '@sanity/cli-core'\n\nimport {FEDERATION_FILE_NAME, RUNTIME_DIR} from './actions/build/vite/constants.js'\nimport {\n type Dock,\n interfaceContractVersion,\n type InterfaceKind,\n interfaceModuleId,\n type TileInterfaceMetadata,\n type ViewPlacementMetadata,\n} from './contract.js'\nimport {isWorkbenchApp} from './defineApp.js'\n\n/** What a studio exposes as `./App` — the generated entry that renders `sanity.config.ts`. */\nconst GENERATED_ENTRY = `./${RUNTIME_DIR}/${FEDERATION_FILE_NAME}.jsx`\n\ninterface DerivedInterfaceBase {\n /** CLI-minted for a local interface; a deployed one gets its id from Brett. */\n id: string\n moduleId: string\n name: string\n src: string\n title: string\n\n version?: string\n}\n\n/** @internal */\nexport type DerivedInterface =\n | (DerivedInterfaceBase & {metadata: null; surface: 'asset_source'})\n | (DerivedInterfaceBase & {metadata: null; type: 'worker'})\n | (DerivedInterfaceBase & {metadata: TileInterfaceMetadata; surface: 'tile'})\n | (DerivedInterfaceBase & {metadata: ViewPlacementMetadata | null; surface: 'app'})\n | (DerivedInterfaceBase & {metadata: ViewPlacementMetadata | null; surface: 'panel'})\n\n/**\n * `appTitle` titles the app view where a deploy resolved one through `--title`;\n * dev takes it from the config.\n * @internal\n */\nexport function deriveInterfaces(\n app: CliConfig['app'],\n {appTitle, isApp}: {appTitle?: string; isApp: boolean},\n): DerivedInterface[] {\n if (!isWorkbenchApp(app)) return []\n\n // The schema rejects a *declared* studio with an `entry`; `isApp` is resolved\n // from the project, so a detected one only fails here.\n if (!isApp && app.entry !== undefined) {\n throw new Error('App views for studios are not implemented yet')\n }\n const entry = isApp ? app.entry : GENERATED_ENTRY\n\n // Identity, not address: interface ids and the app-view name key on `name`\n // (which defaults to `slug`, so existing apps derive byte-identical ids).\n const appName = app.name ?? app.slug\n\n const shared = (\n kind: InterfaceKind,\n declaration: {name: string; src: string; title: string},\n ) => ({\n id: `${appName}-${kind}-${declaration.name}`,\n moduleId: interfaceModuleId(kind, declaration.name),\n name: declaration.name,\n src: declaration.src,\n title: declaration.title,\n version: interfaceContractVersion(kind),\n })\n\n const placementMetadata = (dock?: Dock): ViewPlacementMetadata | null => {\n const group = dock?.group ?? app.dock?.group\n const order = dock?.order ?? app.dock?.order\n if (group === undefined && order === undefined) return null\n return {\n dock: {\n ...(group === undefined ? {} : {group}),\n ...(order === undefined ? {} : {order}),\n },\n }\n }\n\n return [\n ...(app.views ?? []).map((view): DerivedInterface => {\n if (view.surface === 'tile') {\n return {\n ...shared(view.surface, view),\n metadata:\n view.order === undefined ? {size: view.size} : {order: view.order, size: view.size},\n surface: view.surface,\n }\n }\n if (view.surface === 'app' || view.surface === 'panel') {\n return {\n ...shared(view.surface, view),\n metadata: placementMetadata(view.dock),\n surface: view.surface,\n }\n }\n return {...shared(view.surface, view), metadata: null, surface: view.surface}\n }),\n ...(app.webWorkers ?? []).map(\n (webWorker): DerivedInterface => ({\n ...shared('worker', webWorker),\n metadata: null,\n type: 'worker',\n }),\n ),\n ...(entry === undefined\n ? []\n : [\n {\n ...shared('app', {name: appName, src: entry, title: appTitle ?? app.title}),\n metadata: placementMetadata(),\n surface: 'app' as const,\n },\n ]),\n ]\n}\n"],"names":["FEDERATION_FILE_NAME","RUNTIME_DIR","interfaceContractVersion","interfaceModuleId","isWorkbenchApp","GENERATED_ENTRY","deriveInterfaces","app","appTitle","isApp","entry","undefined","Error","appName","name","slug","shared","kind","declaration","id","moduleId","src","title","version","placementMetadata","dock","group","order","views","map","view","surface","metadata","size","webWorkers","webWorker","type"],"mappings":"AAEA,SAAQA,oBAAoB,EAAEC,WAAW,QAAO,oCAAmC;AACnF,SAEEC,wBAAwB,EAExBC,iBAAiB,QAGZ,gBAAe;AACtB,SAAQC,cAAc,QAAO,iBAAgB;AAE7C,4FAA4F,GAC5F,MAAMC,kBAAkB,CAAC,EAAE,EAAEJ,YAAY,CAAC,EAAED,qBAAqB,IAAI,CAAC;AAqBtE;;;;CAIC,GACD,OAAO,SAASM,iBACdC,GAAqB,EACrB,EAACC,QAAQ,EAAEC,KAAK,EAAsC;IAEtD,IAAI,CAACL,eAAeG,MAAM,OAAO,EAAE;IAEnC,8EAA8E;IAC9E,uDAAuD;IACvD,IAAI,CAACE,SAASF,IAAIG,KAAK,KAAKC,WAAW;QACrC,MAAM,IAAIC,MAAM;IAClB;IACA,MAAMF,QAAQD,QAAQF,IAAIG,KAAK,GAAGL;IAElC,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAMQ,UAAUN,IAAIO,IAAI,IAAIP,IAAIQ,IAAI;IAEpC,MAAMC,SAAS,CACbC,MACAC,cACI,CAAA;YACJC,IAAI,GAAGN,QAAQ,CAAC,EAAEI,KAAK,CAAC,EAAEC,YAAYJ,IAAI,EAAE;YAC5CM,UAAUjB,kBAAkBc,MAAMC,YAAYJ,IAAI;YAClDA,MAAMI,YAAYJ,IAAI;YACtBO,KAAKH,YAAYG,GAAG;YACpBC,OAAOJ,YAAYI,KAAK;YACxBC,SAASrB,yBAAyBe;QACpC,CAAA;IAEA,MAAMO,oBAAoB,CAACC;QACzB,MAAMC,QAAQD,MAAMC,SAASnB,IAAIkB,IAAI,EAAEC;QACvC,MAAMC,QAAQF,MAAME,SAASpB,IAAIkB,IAAI,EAAEE;QACvC,IAAID,UAAUf,aAAagB,UAAUhB,WAAW,OAAO;QACvD,OAAO;YACLc,MAAM;gBACJ,GAAIC,UAAUf,YAAY,CAAC,IAAI;oBAACe;gBAAK,CAAC;gBACtC,GAAIC,UAAUhB,YAAY,CAAC,IAAI;oBAACgB;gBAAK,CAAC;YACxC;QACF;IACF;IAEA,OAAO;WACF,AAACpB,CAAAA,IAAIqB,KAAK,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC;YACxB,IAAIA,KAAKC,OAAO,KAAK,QAAQ;gBAC3B,OAAO;oBACL,GAAGf,OAAOc,KAAKC,OAAO,EAAED,KAAK;oBAC7BE,UACEF,KAAKH,KAAK,KAAKhB,YAAY;wBAACsB,MAAMH,KAAKG,IAAI;oBAAA,IAAI;wBAACN,OAAOG,KAAKH,KAAK;wBAAEM,MAAMH,KAAKG,IAAI;oBAAA;oBACpFF,SAASD,KAAKC,OAAO;gBACvB;YACF;YACA,IAAID,KAAKC,OAAO,KAAK,SAASD,KAAKC,OAAO,KAAK,SAAS;gBACtD,OAAO;oBACL,GAAGf,OAAOc,KAAKC,OAAO,EAAED,KAAK;oBAC7BE,UAAUR,kBAAkBM,KAAKL,IAAI;oBACrCM,SAASD,KAAKC,OAAO;gBACvB;YACF;YACA,OAAO;gBAAC,GAAGf,OAAOc,KAAKC,OAAO,EAAED,KAAK;gBAAEE,UAAU;gBAAMD,SAASD,KAAKC,OAAO;YAAA;QAC9E;WACG,AAACxB,CAAAA,IAAI2B,UAAU,IAAI,EAAE,AAAD,EAAGL,GAAG,CAC3B,CAACM,YAAiC,CAAA;gBAChC,GAAGnB,OAAO,UAAUmB,UAAU;gBAC9BH,UAAU;gBACVI,MAAM;YACR,CAAA;WAEE1B,UAAUC,YACV,EAAE,GACF;YACE;gBACE,GAAGK,OAAO,OAAO;oBAACF,MAAMD;oBAASQ,KAAKX;oBAAOY,OAAOd,YAAYD,IAAIe,KAAK;gBAAA,EAAE;gBAC3EU,UAAUR;gBACVO,SAAS;YACX;SACD;KACN;AACH"}
@@ -0,0 +1,63 @@
1
+ /// <reference types="vite/client" />
2
+ // Keep this module browser-safe: Vite loads it directly in the generated dashboard runtime.
3
+ import { createInstance } from '@module-federation/runtime';
4
+ import { BehaviorSubject } from 'rxjs';
5
+ const remoteName = 'workbench-remote';
6
+ const remoteModuleId = `${remoteName}/App`;
7
+ const localApplicationsEvent = 'sanity:workbench:local-applications';
8
+ const noop = ()=>{};
9
+ export async function renderDashboard(rootElement, config, options) {
10
+ if (!rootElement) {
11
+ throw new Error('Missing root element to mount application into');
12
+ }
13
+ const deployedDashboardHost = globalThis.__SANITY_STAGING__ === true ? 'workbench-apps-of5p8qpku.run.sanity.work' : 'workbench-apps-osyh1iet5.sanity.run';
14
+ const remoteUrl = import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL ?? `https://${deployedDashboardHost}/mf-manifest.json`;
15
+ const federation = createInstance({
16
+ name: 'sanity-workbench',
17
+ remotes: [
18
+ {
19
+ entry: remoteUrl,
20
+ name: remoteName
21
+ }
22
+ ]
23
+ });
24
+ let remoteModule;
25
+ try {
26
+ remoteModule = await federation.loadRemote(remoteModuleId);
27
+ } catch (error) {
28
+ throw new Error(`Failed to load remote module "${remoteModuleId}"`, {
29
+ cause: error
30
+ });
31
+ }
32
+ if (!remoteModule || typeof remoteModule.render !== 'function') {
33
+ throw new Error(`Remote module "${remoteModuleId}" did not expose a render function`);
34
+ }
35
+ let appConfigs;
36
+ let cleanupHmr = noop;
37
+ let localApplications;
38
+ if (import.meta.hot) {
39
+ const hot = import.meta.hot;
40
+ const hmrLocalApplications = new BehaviorSubject([]);
41
+ const hmrAppConfigs = new BehaviorSubject([]);
42
+ const handler = (payload)=>{
43
+ hmrLocalApplications.next(payload.applications);
44
+ hmrAppConfigs.next(payload.configs ?? []);
45
+ };
46
+ localApplications = hmrLocalApplications;
47
+ appConfigs = hmrAppConfigs;
48
+ hot.on(localApplicationsEvent, handler);
49
+ hot.send('sanity:workbench:get-local-applications');
50
+ cleanupHmr = ()=>hot.off(localApplicationsEvent, handler);
51
+ }
52
+ const unmount = remoteModule.render(rootElement, {
53
+ appConfigs,
54
+ config,
55
+ localApplications
56
+ }, options);
57
+ return ()=>{
58
+ cleanupHmr();
59
+ unmount();
60
+ };
61
+ }
62
+
63
+ //# sourceMappingURL=renderDashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/renderDashboard.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\n\n// Keep this module browser-safe: Vite loads it directly in the generated dashboard runtime.\nimport {createInstance} from '@module-federation/runtime'\nimport {BehaviorSubject, type Observable} from 'rxjs'\n\ndeclare global {\n var __SANITY_STAGING__: boolean | undefined\n}\n\ninterface DashboardConfig {\n organizationId: string\n}\n\ninterface RenderDashboardOptions {\n reactStrictMode?: boolean\n}\n\ninterface DashboardRemoteModule {\n render: (\n rootElement: HTMLElement,\n props: {\n appConfigs?: Observable<unknown[]>\n config: DashboardConfig\n localApplications?: Observable<unknown[]>\n },\n options?: RenderDashboardOptions,\n ) => () => void\n}\n\nconst remoteName = 'workbench-remote'\nconst remoteModuleId = `${remoteName}/App`\nconst localApplicationsEvent = 'sanity:workbench:local-applications'\nconst noop = () => {}\n\nexport async function renderDashboard(\n rootElement: HTMLElement | null,\n config: DashboardConfig,\n options?: RenderDashboardOptions,\n): Promise<() => void> {\n if (!rootElement) {\n throw new Error('Missing root element to mount application into')\n }\n\n const deployedDashboardHost =\n globalThis.__SANITY_STAGING__ === true\n ? 'workbench-apps-of5p8qpku.run.sanity.work'\n : 'workbench-apps-osyh1iet5.sanity.run'\n const remoteUrl =\n import.meta.env.SANITY_INTERNAL_WORKBENCH_REMOTE_URL ??\n `https://${deployedDashboardHost}/mf-manifest.json`\n\n const federation = createInstance({\n name: 'sanity-workbench',\n remotes: [{entry: remoteUrl, name: remoteName}],\n })\n\n let remoteModule: DashboardRemoteModule | null\n try {\n remoteModule = await federation.loadRemote<DashboardRemoteModule>(remoteModuleId)\n } catch (error) {\n throw new Error(`Failed to load remote module \"${remoteModuleId}\"`, {cause: error})\n }\n\n if (!remoteModule || typeof remoteModule.render !== 'function') {\n throw new Error(`Remote module \"${remoteModuleId}\" did not expose a render function`)\n }\n\n let appConfigs: BehaviorSubject<unknown[]> | undefined\n let cleanupHmr = noop\n let localApplications: BehaviorSubject<unknown[]> | undefined\n\n if (import.meta.hot) {\n const hot = import.meta.hot\n const hmrLocalApplications = new BehaviorSubject<unknown[]>([])\n const hmrAppConfigs = new BehaviorSubject<unknown[]>([])\n const handler = (payload: {applications: unknown[]; configs?: unknown[]}) => {\n hmrLocalApplications.next(payload.applications)\n hmrAppConfigs.next(payload.configs ?? [])\n }\n\n localApplications = hmrLocalApplications\n appConfigs = hmrAppConfigs\n hot.on(localApplicationsEvent, handler)\n hot.send('sanity:workbench:get-local-applications')\n cleanupHmr = () => hot.off(localApplicationsEvent, handler)\n }\n\n const unmount = remoteModule.render(rootElement, {appConfigs, config, localApplications}, options)\n\n return () => {\n cleanupHmr()\n unmount()\n }\n}\n"],"names":["createInstance","BehaviorSubject","remoteName","remoteModuleId","localApplicationsEvent","noop","renderDashboard","rootElement","config","options","Error","deployedDashboardHost","globalThis","__SANITY_STAGING__","remoteUrl","env","SANITY_INTERNAL_WORKBENCH_REMOTE_URL","federation","name","remotes","entry","remoteModule","loadRemote","error","cause","render","appConfigs","cleanupHmr","localApplications","hot","hmrLocalApplications","hmrAppConfigs","handler","payload","next","applications","configs","on","send","off","unmount"],"mappings":"AAAA,qCAAqC;AAErC,4FAA4F;AAC5F,SAAQA,cAAc,QAAO,6BAA4B;AACzD,SAAQC,eAAe,QAAwB,OAAM;AA0BrD,MAAMC,aAAa;AACnB,MAAMC,iBAAiB,GAAGD,WAAW,IAAI,CAAC;AAC1C,MAAME,yBAAyB;AAC/B,MAAMC,OAAO,KAAO;AAEpB,OAAO,eAAeC,gBACpBC,WAA+B,EAC/BC,MAAuB,EACvBC,OAAgC;IAEhC,IAAI,CAACF,aAAa;QAChB,MAAM,IAAIG,MAAM;IAClB;IAEA,MAAMC,wBACJC,WAAWC,kBAAkB,KAAK,OAC9B,6CACA;IACN,MAAMC,YACJ,YAAYC,GAAG,CAACC,oCAAoC,IACpD,CAAC,QAAQ,EAAEL,sBAAsB,iBAAiB,CAAC;IAErD,MAAMM,aAAajB,eAAe;QAChCkB,MAAM;QACNC,SAAS;YAAC;gBAACC,OAAON;gBAAWI,MAAMhB;YAAU;SAAE;IACjD;IAEA,IAAImB;IACJ,IAAI;QACFA,eAAe,MAAMJ,WAAWK,UAAU,CAAwBnB;IACpE,EAAE,OAAOoB,OAAO;QACd,MAAM,IAAIb,MAAM,CAAC,8BAA8B,EAAEP,eAAe,CAAC,CAAC,EAAE;YAACqB,OAAOD;QAAK;IACnF;IAEA,IAAI,CAACF,gBAAgB,OAAOA,aAAaI,MAAM,KAAK,YAAY;QAC9D,MAAM,IAAIf,MAAM,CAAC,eAAe,EAAEP,eAAe,kCAAkC,CAAC;IACtF;IAEA,IAAIuB;IACJ,IAAIC,aAAatB;IACjB,IAAIuB;IAEJ,IAAI,YAAYC,GAAG,EAAE;QACnB,MAAMA,MAAM,YAAYA,GAAG;QAC3B,MAAMC,uBAAuB,IAAI7B,gBAA2B,EAAE;QAC9D,MAAM8B,gBAAgB,IAAI9B,gBAA2B,EAAE;QACvD,MAAM+B,UAAU,CAACC;YACfH,qBAAqBI,IAAI,CAACD,QAAQE,YAAY;YAC9CJ,cAAcG,IAAI,CAACD,QAAQG,OAAO,IAAI,EAAE;QAC1C;QAEAR,oBAAoBE;QACpBJ,aAAaK;QACbF,IAAIQ,EAAE,CAACjC,wBAAwB4B;QAC/BH,IAAIS,IAAI,CAAC;QACTX,aAAa,IAAME,IAAIU,GAAG,CAACnC,wBAAwB4B;IACrD;IAEA,MAAMQ,UAAUnB,aAAaI,MAAM,CAAClB,aAAa;QAACmB;QAAYlB;QAAQoB;IAAiB,GAAGnB;IAE1F,OAAO;QACLkB;QACAa;IACF;AACF"}
@@ -1,29 +1,33 @@
1
1
  // Package-internal shared resolver: turn a CLI config's branded
2
- // `unstable_defineApp` app into its declared interfaces, or `null` for a plain
3
- // project. The build and deploy accessors (actions/build, actions/deploy) each
4
- // build their command-specific view on top of this one brand-check +
2
+ // `defineApplication` app into its declared interfaces, or `null` for a plain
3
+ // project and for a config (a branded `unstable_defineMediaLibrary`), which
4
+ // is not an app. The build and deploy accessors (actions/build, actions/deploy)
5
+ // each build their command-specific view on top of this one brand-check +
5
6
  // extraction, so the discrimination lives in exactly one place.
6
- import { isWorkbenchApp, readConfig } from './defineApp.js';
7
+ import { isWorkbenchApp } from './defineApp.js';
7
8
  import { formatWorkbenchAppErrors, validateWorkbenchApp } from './validateWorkbenchApp.js';
8
9
  /**
9
- * Resolve the workbench app for a CLI config, or `null` for a plain project.
10
+ * Resolve the workbench app for a CLI config, or `null` for a plain project or a
11
+ * config (which is not an app — read it with `resolveWorkbenchConfig`).
10
12
  * @public
11
13
  */ export function resolveWorkbenchApp(cliConfig) {
12
14
  const app = cliConfig?.app;
15
+ // A config carries a distinct brand, so `isWorkbenchApp` is false for it — it
16
+ // resolves to `null` here, like a plain project.
13
17
  if (!isWorkbenchApp(app)) return null;
14
18
  const errors = validateWorkbenchApp(app);
15
19
  if (errors.length > 0) throw new Error(formatWorkbenchAppErrors(errors));
16
20
  return {
17
21
  applicationType: app.applicationType,
18
- config: readConfig(app),
19
22
  entry: app.entry,
20
23
  icon: app.icon,
21
- isSingleton: app.isSingleton,
24
+ // Identity defaults to the address, so existing apps behave identically.
25
+ name: app.name ?? app.slug,
22
26
  organizationId: app.organizationId,
23
- services: app.services ?? [],
24
27
  slug: app.slug,
25
28
  views: app.views ?? [],
26
- visibility: app.visibility
29
+ visibility: app.visibility,
30
+ webWorkers: app.webWorkers ?? []
27
31
  };
28
32
  }
29
33
 
@@ -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 AppVisibility, type CliConfig} from '@sanity/cli-core'\n\nimport {type DefineAppInput, isWorkbenchApp, readConfig, type WorkbenchApp} from './defineApp.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from './validateWorkbenchApp.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 /** Organization that owns the app — part of its build-id identity. */\n readonly organizationId: string\n /** Background worker services the app declares. */\n readonly services: NonNullable<DefineAppInput['services']>\n\n readonly slug: string\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 /** 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 const errors = validateWorkbenchApp(app)\n if (errors.length > 0) throw new Error(formatWorkbenchAppErrors(errors))\n\n return {\n applicationType: app.applicationType,\n config: readConfig(app),\n entry: app.entry,\n icon: app.icon,\n isSingleton: app.isSingleton,\n organizationId: app.organizationId,\n services: app.services ?? [],\n slug: app.slug,\n views: app.views ?? [],\n visibility: app.visibility,\n }\n}\n"],"names":["isWorkbenchApp","readConfig","formatWorkbenchAppErrors","validateWorkbenchApp","resolveWorkbenchApp","cliConfig","app","errors","length","Error","applicationType","config","entry","icon","isSingleton","organizationId","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;AACjG,SAAQC,wBAAwB,EAAEC,oBAAoB,QAAO,4BAA2B;AAuCxF;;;CAGC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,IAAI,CAACN,eAAeM,MAAM,OAAO;IAEjC,MAAMC,SAASJ,qBAAqBG;IACpC,IAAIC,OAAOC,MAAM,GAAG,GAAG,MAAM,IAAIC,MAAMP,yBAAyBK;IAEhE,OAAO;QACLG,iBAAiBJ,IAAII,eAAe;QACpCC,QAAQV,WAAWK;QACnBM,OAAON,IAAIM,KAAK;QAChBC,MAAMP,IAAIO,IAAI;QACdC,aAAaR,IAAIQ,WAAW;QAC5BC,gBAAgBT,IAAIS,cAAc;QAClCC,UAAUV,IAAIU,QAAQ,IAAI,EAAE;QAC5BC,MAAMX,IAAIW,IAAI;QACdC,OAAOZ,IAAIY,KAAK,IAAI,EAAE;QACtBC,YAAYb,IAAIa,UAAU;IAC5B;AACF"}
1
+ {"version":3,"sources":["../src/resolveWorkbenchApp.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `defineApplication` app into its declared interfaces, or `null` for a plain\n// project — and for a config (a branded `unstable_defineMediaLibrary`), which\n// is not an app. The build and deploy accessors (actions/build, actions/deploy)\n// each 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 WorkbenchConfigValue} from './contract.js'\nimport {type DefineAppInput, isWorkbenchApp} from './defineApp.js'\nimport {formatWorkbenchAppErrors, validateWorkbenchApp} from './validateWorkbenchApp.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. `config` is sourced\n * from `resolveWorkbenchConfig` (a config is not an app), not from this resolver.\n * @internal\n */\nexport interface WorkbenchExposes {\n config?: WorkbenchConfigValue\n views?: DefineAppInput['views']\n webWorkers?: DefineAppInput['webWorkers']\n}\n\n/** @public */\nexport interface ResolvedWorkbenchApp {\n /**\n * Stable identity, distinct from the `slug` address. Defaults to `slug`, and is\n * what every identity key (build id, interface ids) is built from.\n */\n readonly name: string\n /** Organization that owns the app — part of its build-id identity. */\n readonly organizationId: string\n readonly slug: string\n\n /** Views the app declares. */\n readonly views: NonNullable<DefineAppInput['views']>\n\n /** Background web workers the app declares. */\n readonly webWorkers: NonNullable<DefineAppInput['webWorkers']>\n\n /** Resolved app kind — `studio` or one of the SDK app types. */\n readonly applicationType?: string\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 /** 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 or a\n * config (which is not an app — read it with `resolveWorkbenchConfig`).\n * @public\n */\nexport function resolveWorkbenchApp(\n cliConfig: CliConfig | null | undefined,\n): ResolvedWorkbenchApp | null {\n const app = cliConfig?.app\n // A config carries a distinct brand, so `isWorkbenchApp` is false for it — it\n // resolves to `null` here, like a plain project.\n if (!isWorkbenchApp(app)) return null\n\n const errors = validateWorkbenchApp(app)\n if (errors.length > 0) throw new Error(formatWorkbenchAppErrors(errors))\n\n return {\n applicationType: app.applicationType,\n entry: app.entry,\n icon: app.icon,\n // Identity defaults to the address, so existing apps behave identically.\n name: app.name ?? app.slug,\n organizationId: app.organizationId,\n slug: app.slug,\n views: app.views ?? [],\n visibility: app.visibility,\n webWorkers: app.webWorkers ?? [],\n }\n}\n"],"names":["isWorkbenchApp","formatWorkbenchAppErrors","validateWorkbenchApp","resolveWorkbenchApp","cliConfig","app","errors","length","Error","applicationType","entry","icon","name","slug","organizationId","views","visibility","webWorkers"],"mappings":"AAAA,gEAAgE;AAChE,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,0EAA0E;AAC1E,gEAAgE;AAKhE,SAA6BA,cAAc,QAAO,iBAAgB;AAClE,SAAQC,wBAAwB,EAAEC,oBAAoB,QAAO,4BAA2B;AAyCxF;;;;CAIC,GACD,OAAO,SAASC,oBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,8EAA8E;IAC9E,iDAAiD;IACjD,IAAI,CAACL,eAAeK,MAAM,OAAO;IAEjC,MAAMC,SAASJ,qBAAqBG;IACpC,IAAIC,OAAOC,MAAM,GAAG,GAAG,MAAM,IAAIC,MAAMP,yBAAyBK;IAEhE,OAAO;QACLG,iBAAiBJ,IAAII,eAAe;QACpCC,OAAOL,IAAIK,KAAK;QAChBC,MAAMN,IAAIM,IAAI;QACd,yEAAyE;QACzEC,MAAMP,IAAIO,IAAI,IAAIP,IAAIQ,IAAI;QAC1BC,gBAAgBT,IAAIS,cAAc;QAClCD,MAAMR,IAAIQ,IAAI;QACdE,OAAOV,IAAIU,KAAK,IAAI,EAAE;QACtBC,YAAYX,IAAIW,UAAU;QAC1BC,YAAYZ,IAAIY,UAAU,IAAI,EAAE;IAClC;AACF"}
@@ -0,0 +1,30 @@
1
+ // Package-internal shared resolver: turn a CLI config's branded
2
+ // `unstable_defineMediaLibrary` config into its target `appType`, owning
3
+ // `organizationId`, and `fields`, or `null` when the config is not a config
4
+ // (a plain project or an app). The deploy/undeploy/build paths consult this
5
+ // second resolver; app-only callers keep using `resolveWorkbenchApp`.
6
+ import { ConfigSchema } from './contract.js';
7
+ import { isWorkbenchConfig } from './defineApp.js';
8
+ /**
9
+ * Resolve the workbench config for a CLI config, or `null` when it carries no
10
+ * config brand (a plain project or an app). The only config today is the Media
11
+ * Library, so the resolved shape is a {@link ResolvedMediaLibraryConfig}.
12
+ * @public
13
+ */ export function resolveWorkbenchConfig(cliConfig) {
14
+ const app = cliConfig?.app;
15
+ if (!isWorkbenchConfig(app)) return null;
16
+ const result = ConfigSchema.safeParse({
17
+ appType: app.appType,
18
+ fields: app.fields
19
+ });
20
+ if (!result.success) {
21
+ throw new Error(`Invalid workbench config: ${result.error.message}`);
22
+ }
23
+ return {
24
+ appType: app.appType,
25
+ fields: app.fields,
26
+ organizationId: app.organizationId
27
+ };
28
+ }
29
+
30
+ //# sourceMappingURL=resolveWorkbenchConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resolveWorkbenchConfig.ts"],"sourcesContent":["// Package-internal shared resolver: turn a CLI config's branded\n// `unstable_defineMediaLibrary` config into its target `appType`, owning\n// `organizationId`, and `fields`, or `null` when the config is not a config\n// (a plain project or an app). The deploy/undeploy/build paths consult this\n// second resolver; app-only callers keep using `resolveWorkbenchApp`.\n\nimport {type CliConfig} from '@sanity/cli-core'\n\nimport {ConfigSchema, type WorkbenchConfigValue} from './contract.js'\nimport {isWorkbenchConfig} from './defineApp.js'\n\n/** @public */\nexport interface ResolvedMediaLibraryConfig {\n /** Target app the config binds to — resolves the org installation on deploy. */\n readonly appType: WorkbenchConfigValue['appType']\n /** The config's declared fields, expanded into the federation remote on build. */\n readonly fields: WorkbenchConfigValue['fields']\n /** Organization that owns the config's target installation. */\n readonly organizationId: string\n}\n\n/**\n * Resolve the workbench config for a CLI config, or `null` when it carries no\n * config brand (a plain project or an app). The only config today is the Media\n * Library, so the resolved shape is a {@link ResolvedMediaLibraryConfig}.\n * @public\n */\nexport function resolveWorkbenchConfig(\n cliConfig: CliConfig | null | undefined,\n): ResolvedMediaLibraryConfig | null {\n const app = cliConfig?.app\n if (!isWorkbenchConfig(app)) return null\n\n const result = ConfigSchema.safeParse({appType: app.appType, fields: app.fields})\n if (!result.success) {\n throw new Error(`Invalid workbench config: ${result.error.message}`)\n }\n\n return {appType: app.appType, fields: app.fields, organizationId: app.organizationId}\n}\n"],"names":["ConfigSchema","isWorkbenchConfig","resolveWorkbenchConfig","cliConfig","app","result","safeParse","appType","fields","success","Error","error","message","organizationId"],"mappings":"AAAA,gEAAgE;AAChE,yEAAyE;AACzE,4EAA4E;AAC5E,4EAA4E;AAC5E,sEAAsE;AAItE,SAAQA,YAAY,QAAkC,gBAAe;AACrE,SAAQC,iBAAiB,QAAO,iBAAgB;AAYhD;;;;;CAKC,GACD,OAAO,SAASC,uBACdC,SAAuC;IAEvC,MAAMC,MAAMD,WAAWC;IACvB,IAAI,CAACH,kBAAkBG,MAAM,OAAO;IAEpC,MAAMC,SAASL,aAAaM,SAAS,CAAC;QAACC,SAASH,IAAIG,OAAO;QAAEC,QAAQJ,IAAII,MAAM;IAAA;IAC/E,IAAI,CAACH,OAAOI,OAAO,EAAE;QACnB,MAAM,IAAIC,MAAM,CAAC,0BAA0B,EAAEL,OAAOM,KAAK,CAACC,OAAO,EAAE;IACrE;IAEA,OAAO;QAACL,SAASH,IAAIG,OAAO;QAAEC,QAAQJ,IAAII,MAAM;QAAEK,gBAAgBT,IAAIS,cAAc;IAAA;AACtF"}