create-next-hydra 0.2.1 → 0.4.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.
- package/README.md +156 -26
- package/dist/add-command.d.ts +11 -0
- package/dist/add-command.d.ts.map +1 -0
- package/dist/add-command.js +75 -0
- package/dist/addition.d.ts +67 -0
- package/dist/addition.d.ts.map +1 -0
- package/dist/addition.js +422 -0
- package/dist/application-git.d.ts +20 -0
- package/dist/application-git.d.ts.map +1 -0
- package/dist/application-git.js +57 -0
- package/dist/baseline.d.ts +22 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +90 -0
- package/dist/cli.js +5 -18
- package/dist/commands.d.ts +22 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +197 -0
- package/dist/composition-lint.d.ts +20 -0
- package/dist/composition-lint.d.ts.map +1 -0
- package/dist/composition-lint.js +288 -0
- package/dist/composition.d.ts +24 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +420 -0
- package/dist/create-command.d.ts +21 -0
- package/dist/create-command.d.ts.map +1 -0
- package/dist/create-command.js +128 -0
- package/dist/demo-instrumentation.d.ts +5 -0
- package/dist/demo-instrumentation.d.ts.map +1 -0
- package/dist/demo-instrumentation.js +300 -0
- package/dist/environment.d.ts +7 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +81 -0
- package/dist/errors.d.ts +156 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +140 -0
- package/dist/file-policy.d.ts +6 -0
- package/dist/file-policy.d.ts.map +1 -0
- package/dist/file-policy.js +38 -0
- package/dist/files.d.ts +7 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +66 -0
- package/dist/hosting.d.ts +5 -0
- package/dist/hosting.d.ts.map +1 -0
- package/dist/hosting.js +107 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -89
- package/dist/initialization.d.ts +14 -0
- package/dist/initialization.d.ts.map +1 -0
- package/dist/initialization.js +266 -0
- package/dist/lint-workspaces.d.ts +2 -0
- package/dist/lint-workspaces.d.ts.map +1 -0
- package/dist/lint-workspaces.js +62 -0
- package/dist/model.d.ts +143 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +61 -0
- package/dist/package-catalog.d.ts +8 -0
- package/dist/package-catalog.d.ts.map +1 -0
- package/dist/package-catalog.js +61 -0
- package/dist/packages.d.ts +57 -0
- package/dist/packages.d.ts.map +1 -0
- package/dist/packages.js +237 -0
- package/dist/process-group.d.ts +5 -0
- package/dist/process-group.d.ts.map +1 -0
- package/dist/process-group.js +23 -0
- package/dist/reference-workspace-bindings.d.ts +38 -0
- package/dist/reference-workspace-bindings.d.ts.map +1 -0
- package/dist/reference-workspace-bindings.js +41 -0
- package/dist/reference-workspace.d.ts +6 -0
- package/dist/reference-workspace.d.ts.map +1 -0
- package/dist/reference-workspace.js +62 -0
- package/dist/registry.d.ts +187 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +107 -0
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +22 -0
- package/dist/selection.d.ts +704 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +424 -0
- package/dist/shadcn-protocol.d.ts +22 -0
- package/dist/shadcn-protocol.d.ts.map +1 -0
- package/dist/shadcn-protocol.js +13 -0
- package/dist/shadcn-worker.d.ts +2 -0
- package/dist/shadcn-worker.d.ts.map +1 -0
- package/dist/shadcn-worker.js +43 -0
- package/dist/shadcn.d.ts +22 -0
- package/dist/shadcn.d.ts.map +1 -0
- package/dist/shadcn.js +101 -0
- package/dist/source-changes.d.ts +55 -0
- package/dist/source-changes.d.ts.map +1 -0
- package/dist/source-changes.js +225 -0
- package/dist/source-inventory.d.ts +25 -0
- package/dist/source-inventory.d.ts.map +1 -0
- package/dist/source-inventory.js +212 -0
- package/dist/source-root.d.ts +4 -0
- package/dist/source-root.d.ts.map +1 -0
- package/dist/source-root.js +20 -0
- package/dist/staging.d.ts +19 -0
- package/dist/staging.d.ts.map +1 -0
- package/dist/staging.js +42 -0
- package/dist/tasks.d.ts +44 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +137 -0
- package/dist/templates.d.ts +217 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +161 -0
- package/dist/test-reference-workspace.d.ts +2 -0
- package/dist/test-reference-workspace.d.ts.map +1 -0
- package/dist/test-reference-workspace.js +6 -0
- package/dist/types.d.ts +2 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/typescript-paths.d.ts +10 -0
- package/dist/typescript-paths.d.ts.map +1 -0
- package/dist/typescript-paths.js +52 -0
- package/dist/workspace-dependencies.d.ts +26 -0
- package/dist/workspace-dependencies.d.ts.map +1 -0
- package/dist/workspace-dependencies.js +478 -0
- package/dist/workspace-files.d.ts +24 -0
- package/dist/workspace-files.d.ts.map +1 -0
- package/dist/workspace-files.js +395 -0
- package/dist/workspace-lock.d.ts +12 -0
- package/dist/workspace-lock.d.ts.map +1 -0
- package/dist/workspace-lock.js +104 -0
- package/dist/workspace-snapshots.d.ts +24 -0
- package/dist/workspace-snapshots.d.ts.map +1 -0
- package/dist/workspace-snapshots.js +218 -0
- package/dist/workspace-sources.d.ts +27 -0
- package/dist/workspace-sources.d.ts.map +1 -0
- package/dist/workspace-sources.js +88 -0
- package/dist/workspace-state.d.ts +325 -0
- package/dist/workspace-state.d.ts.map +1 -0
- package/dist/workspace-state.js +571 -0
- package/dist/workspaces.d.ts +73 -0
- package/dist/workspaces.d.ts.map +1 -0
- package/dist/workspaces.js +396 -0
- package/package.json +27 -15
- package/schema/selection-definition.json +206 -5
- package/dist/clone.d.ts +0 -9
- package/dist/clone.d.ts.map +0 -1
- package/dist/clone.js +0 -19
- package/dist/composition/add.d.ts +0 -14
- package/dist/composition/add.d.ts.map +0 -1
- package/dist/composition/add.js +0 -453
- package/dist/composition/catalog.d.ts +0 -26
- package/dist/composition/catalog.d.ts.map +0 -1
- package/dist/composition/catalog.js +0 -313
- package/dist/composition/errors.d.ts +0 -5
- package/dist/composition/errors.d.ts.map +0 -1
- package/dist/composition/errors.js +0 -8
- package/dist/composition/format.d.ts +0 -6
- package/dist/composition/format.d.ts.map +0 -1
- package/dist/composition/format.js +0 -63
- package/dist/composition/install.d.ts +0 -16
- package/dist/composition/install.d.ts.map +0 -1
- package/dist/composition/install.js +0 -175
- package/dist/composition/packages.d.ts +0 -6
- package/dist/composition/packages.d.ts.map +0 -1
- package/dist/composition/packages.js +0 -54
- package/dist/composition/paths.d.ts +0 -4
- package/dist/composition/paths.d.ts.map +0 -1
- package/dist/composition/paths.js +0 -47
- package/dist/composition/planner.d.ts +0 -4
- package/dist/composition/planner.d.ts.map +0 -1
- package/dist/composition/planner.js +0 -320
- package/dist/composition/schema.d.ts +0 -235
- package/dist/composition/schema.d.ts.map +0 -1
- package/dist/composition/schema.js +0 -115
- package/dist/composition/types.d.ts +0 -87
- package/dist/composition/types.d.ts.map +0 -1
- package/dist/composition/types.js +0 -6
- package/dist/composition/use.d.ts +0 -23
- package/dist/composition/use.d.ts.map +0 -1
- package/dist/composition/use.js +0 -182
- package/dist/composition/workspace.d.ts +0 -10
- package/dist/composition/workspace.d.ts.map +0 -1
- package/dist/composition/workspace.js +0 -208
- package/dist/constants.d.ts +0 -11
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -38
- package/dist/fs-utils.d.ts +0 -9
- package/dist/fs-utils.d.ts.map +0 -1
- package/dist/fs-utils.js +0 -64
- package/dist/git.d.ts +0 -28
- package/dist/git.d.ts.map +0 -1
- package/dist/git.js +0 -107
- package/dist/instruction-renderer.d.ts +0 -17
- package/dist/instruction-renderer.d.ts.map +0 -1
- package/dist/instruction-renderer.js +0 -132
- package/dist/logger.d.ts +0 -13
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -26
- package/dist/prompts.d.ts +0 -7
- package/dist/prompts.d.ts.map +0 -1
- package/dist/prompts.js +0 -47
- package/dist/sanitize.d.ts +0 -10
- package/dist/sanitize.d.ts.map +0 -1
- package/dist/sanitize.js +0 -23
- package/dist/scaffold.d.ts +0 -7
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/scaffold.js +0 -325
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-next-hydra
|
|
2
2
|
|
|
3
|
-
`create-next-hydra` composes
|
|
3
|
+
`create-next-hydra` composes applications from selected Providers and compatible Add-ons. There is one shared web application: CMS is required, Auth is optional, and Commerce requires Auth. Commerce is installed as one complete package, not separately selectable catalog, cart, or checkout features. It uses [ShadCN registry items](https://ui.shadcn.com/docs/registry/registry-item-json) to copy code and adds stack validation and package-specific manifest changes.
|
|
4
4
|
|
|
5
5
|
## Create a project
|
|
6
6
|
|
|
@@ -10,65 +10,160 @@ Interactive scaffolding asks for every required Provider:
|
|
|
10
10
|
pnpm dlx create-next-hydra@latest my-project
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Search is an optional Provider Slot. Selecting Algolia adds the storefront search pages, header autocomplete, proxy runtime, and `search` CLI command through registry recipes; it currently requires Commerce. CMS-only sites omit Search. The local navigation-search add-on is an alternative header binding and cannot be selected alongside Algolia.
|
|
14
|
+
|
|
15
|
+
For a non-interactive scaffold, select a Provider or explicitly omit each optional slot, or use a Preset:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
pnpm dlx create-next-hydra@latest my-project --yes \
|
|
17
19
|
--auth workos \
|
|
18
20
|
--cms drupal \
|
|
19
|
-
--commerce commercetools
|
|
21
|
+
--commerce commercetools \
|
|
22
|
+
--search algolia
|
|
20
23
|
|
|
21
24
|
pnpm dlx create-next-hydra@latest my-project --yes --preset standard
|
|
25
|
+
|
|
26
|
+
pnpm dlx create-next-hydra@latest content-site --yes \
|
|
27
|
+
--cms contentstack --without auth --without commerce --without search
|
|
22
28
|
```
|
|
23
29
|
|
|
24
30
|
Use `--add-on <selection>` more than once to include compatible Add-ons. A selection can be an official shorthand, a local registry-item JSON file, a URL, a public GitHub address such as `owner/repository/item#ref`, or a configured ShadCN registry name.
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
Use `--repo-url <repository>` to scaffold from another Git repository and `--ref <revision>` to select a revision. Local repository paths, including `--repo-url .`, resolve from the directory where you invoke the command. Scaffolding reads the committed revision, not uncommitted source edits.
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
After installation, the CLI prints setup instructions supplied by the selected registry items. Follow those instructions before starting the application; composition does not run external provisioning commands for you.
|
|
29
35
|
|
|
30
|
-
The
|
|
36
|
+
The project destination must be missing or empty. Named workspaces support safe initialization and updates instead. New applications retain the registry's existing `vercel.json` defaults and app-local skip-CI scripts. Maintainer composition commands and cache-location settings are not added to these files.
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
Projects include Portless. Run `pnpm dev` in the installed project for stable `<app>.<project>.localhost` origins and automatically allocated application ports. The package name is normalized from the destination name without renaming the folder: `My App` becomes `my-app`. The project hostname label also replaces dots/underscores with hyphens and is limited to 63 characters. Package-owned dev scripts, including API tunneling, remain intact. Local HTTPS may require Portless's one-time proxy/certificate setup; remote authentication callback allowlists must match the actual development origins. Drupal's `dev:web` command keeps Portless while pinning the internal frontend port for DDEV revalidation.
|
|
39
|
+
|
|
40
|
+
## Initialize and update named workspaces
|
|
41
|
+
|
|
42
|
+
The preferred maintainer workflow uses definitions in `workspaces/`. New definitions are visible to Git before being committed; no parent ignore exception is needed. Compose seeds a missing workspace-local `.gitignore` with defaults that expose settings and hide materialized output, then leaves that file under your control. An existing file, including an empty one, is never replaced. No `apps` field or app-profile flag is needed: the shared web application is implicit, and selected packages extend its templates.
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
pnpm --filter create-next-hydra compose cms-contentstack --copy-env
|
|
46
|
+
pnpm --filter create-next-hydra compose cms-contentstack
|
|
47
|
+
pnpm --filter create-next-hydra compose --all --copy-env
|
|
48
|
+
pnpm --filter create-next-hydra compose cms-contentstack --watch
|
|
49
|
+
pnpm --filter create-next-hydra compose --all --check
|
|
50
|
+
pnpm --filter create-next-hydra compose cms-contentstack --explain 'apps/web/app/[locale]/layout.tsx'
|
|
51
|
+
pnpm --dir workspaces/cms-contentstack typecheck
|
|
52
|
+
pnpm --dir workspaces/cms-contentstack dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The same command initializes or updates the same folder. All files are physical copies, including ordinary source and template output. Refresh preserves caches and does not reinstall unchanged dependencies. Unowned local files remain untouched and do not block refresh or `--check`. Conflicting edits to managed files and unowned files occupying new output targets still block changes. `--diff` lists eligible unowned files for optional reconciliation without adopting them. `--no-install` lets you manage installation yourself with pnpm inside the workspace, `--offline` uses the local store, and `--copy-env` explicitly copies only missing local env files. Omit it for deployment. Watch uses the same synchronization and installation policy on every refresh; it does not run an application server. External provisioning is separate.
|
|
56
|
+
|
|
57
|
+
`--check` verifies that composed files match the current definition and source. It does not inspect `.npmrc` or installed dependencies, and it does not run pnpm. A files-only composition can pass Check before dependencies are installed. Install dependencies separately before running application commands.
|
|
58
|
+
|
|
59
|
+
See [Named workspaces](../../workspaces/README.md) for the four definitions, stable Portless hostnames, deployment settings, interruption recovery, and reconciliation instructions. Definitions, workspace-owned `.gitignore` files, optional READMEs, app-local `vercel.json` settings are tracked; materialized runtime manifests, installed files and applied state are ignored. Compose preserves these ignore rules rather than regenerating them. The workspace name determines each Next app's `<app>.<workspace>.localhost` hostname (with Portless's branch prefix inside a Git worktree).
|
|
60
|
+
|
|
61
|
+
Adding a definition or changing its selection requires no task-inventory synchronization. Compose it, then run Turbo inside its installed workspace. Deployments compose directly and use ordinary application-task caching. The source checkout's pnpm workspace declarations still supply canonical package discovery. A filtered tooling install can omit source application dependencies; see [application-root caching](../../workspaces/README.md#application-root-caching).
|
|
62
|
+
|
|
63
|
+
## Command boundaries
|
|
64
|
+
|
|
65
|
+
- `create-next-hydra <directory>` creates a project. It acquires the requested source revision in a temporary directory, constructs only selected files and hands over ordinary copied source. There is no ongoing composition step.
|
|
66
|
+
- `create-next-hydra compose <name>` initializes or refreshes a named workspace from canonical source. Application source is always copied. `compose --all` covers Git-visible definitions, including new untracked ones; `compose --all --check` checks their local state.
|
|
67
|
+
- `create-next-hydra add <item>` adds registry items to an existing project.
|
|
68
|
+
|
|
69
|
+
The source checkout contains canonical modules, templates and registry ownership; runnable applications live in named workspaces. `--explain <file>` shows the selected owner and edit location without updating. Compose explicitly before running application tasks inside the workspace's own Turbo graph. Root `pnpm test` runs package/provider suites and composition checks from source, with common app integration tests only in that WorkOS + Contentstack + commercetools reference; root build/typecheck target the composition CLI. Project creation and named composition share preparation for the baseline, selected files, dependency closure, registry transformations, templates, aliases and patches. Scaffolding owns source acquisition and Git initialization; named composition owns safe refresh and local change inspection.
|
|
70
|
+
|
|
71
|
+
## Deploy a named workspace
|
|
72
|
+
|
|
73
|
+
Deploy the same named folder used for development:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
pnpm --filter create-next-hydra compose storefront-contentstack
|
|
77
|
+
pnpm --dir workspaces/storefront-contentstack exec turbo run build --filter=web
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Named composition uses the same application task configuration as project creation. Source, dependency and environment changes invalidate caches; unchanged inputs can restore prior outputs. Host-specific cache placement belongs in the build invocation, not a different generated Turbo configuration. Portless remains installed; named workspaces retain optional `development.port`; source credentials are copied only with explicit `--copy-env`. Existing destination environment files are preserved, not scrubbed.
|
|
81
|
+
|
|
82
|
+
Put selections in `next-hydra.json`. Compose updates that named folder and preserves caches automatically. Use the root creation command for a new application. See [Vercel configuration and installation order](../../workspaces/README.md#deploy-a-composed-application).
|
|
83
|
+
|
|
84
|
+
## Local source authoring and environment files
|
|
85
|
+
|
|
86
|
+
Use a named definition and `compose <name>` for local development. Add `--copy-env` when you want to initialize missing environment files from your checkout.
|
|
87
|
+
|
|
88
|
+
Each workspace has its own manifests, lockfile, dependencies and physical application files. Canonical modules, template output and third-party registry content use the same materialization as scaffolded projects. Provider aliases and application runtime aliases resolve inside that workspace; no maintainer-only resolution layer is installed.
|
|
89
|
+
|
|
90
|
+
With `--copy-env`, ignored local environment files named `.env` or `.env.*` are copied into matching materialized paths. The primary checkout supplies defaults; the current worktree takes precedence. Copies have owner-only permissions (`0600`). Existing destination files are preserved; occupied non-file destinations are rejected before copying; dependency/build directories and example files are excluded. Contents are never printed or recorded in ownership state or Git snapshots. Composition does not seed values from examples: provisioning owns that. These are local credentials, not distribution assets, and unused capability credentials inside a selected env file are not filtered out.
|
|
91
|
+
|
|
92
|
+
Provider-owned application files are copied from their canonical registry sources. Use `--explain <file>` when the edit location is unclear, edit that source, then refresh. Selection changes never rewrite tracked source applications or manifests.
|
|
93
|
+
|
|
94
|
+
Authoring constraints:
|
|
95
|
+
|
|
96
|
+
- New files and edits to physical copies are **work to preserve**. Named workspaces provide `compose --check`, but adoption remains manual. Reconcile changes into canonical source and registry ownership, run `pnpm registry:sync` and `pnpm registry:check`, then refresh and verify the same workspace. Preserve unreconciled output until this is done; applied state is not a backup.
|
|
97
|
+
- Refresh the same workspace after changing selections, templates, or dependency manifests. Failed updates preserve before/after fingerprints and can be retried after resolving the reported issue.
|
|
98
|
+
|
|
99
|
+
Named workspaces maintain `.workspace-composition.json` ownership fingerprints for safe refresh and save a private Git snapshot outside the application: `compose <name> --diff` shows local edits, deletions and unregistered files, while `--explain` without a filename lists selected files and their canonical edit locations. See [Inspect workspace changes](../../workspaces/README.md#inspect-workspace-changes) for the authoring workflow and exclusions. This is not application runtime input. Project creation retains no receipt, private snapshot or source-root metadata and requires no ongoing generation step.
|
|
100
|
+
|
|
101
|
+
## Verification
|
|
102
|
+
|
|
103
|
+
The implementation uses one shared planner and module-reference renderer. Composition recipes bind normal modules into shared templates; materialized modules have ordinary filenames. The CLI builds with its own pinned TypeScript compiler rather than depending on a root-level executable.
|
|
104
|
+
|
|
105
|
+
Composition lint runs optional package `lint:prepare` scripts in its disposable workspace before checking types. Use these for local generated modules, such as the Drupal Canvas component registry; they must not require credentials or provision external services.
|
|
106
|
+
|
|
107
|
+
Run the bounded local suite before accepting composition changes:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
33
110
|
pnpm --filter create-next-hydra build
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
node packages/create-next-hydra/dist/cli.js
|
|
111
|
+
pnpm --filter create-next-hydra test --maxWorkers 2 --testTimeout 30000
|
|
112
|
+
pnpm registry:check
|
|
113
|
+
node packages/create-next-hydra/dist/cli.js compose --all --check
|
|
37
114
|
```
|
|
38
115
|
|
|
39
|
-
|
|
116
|
+
The suite checks materialization, template ownership and path collisions, working-tree deletions, environment isolation, overwrite refusal, installation recovery, observation and package closure through the workspace and CLI boundaries. Install-heavy E2E tests use the executable to create independent applications and need sufficient local disk/store capacity. Filesystem paths are trusted; ownership checks are not a sandbox for hostile package lifecycle scripts or concurrent directory mutation. See the [implementation guide](src/README.md) for services, state, packaging exercises and platform limits.
|
|
40
117
|
|
|
41
|
-
|
|
118
|
+
Live watcher fixtures resolve their temporary root with `FileSystem.realPath` before deriving source and application paths. Preserve this when adding fixtures: on macOS, `/var/folders/...` can refer to the same directory as `/private/var/folders/...`, while native watcher events use the physical path. Comparing these different path strings can discard valid events and cause timeouts. If watcher tests time out, check the fixture root and reported event paths before increasing timeouts or attributing the failure to a code change. The normal test command requires no `TMPDIR` override.
|
|
42
119
|
|
|
43
|
-
|
|
120
|
+
Whole-package and exact-route materialization are covered by local tests. Named-workspace tests also cover template refresh, dependency retry, local-edit protection, unregistered files and interruption recovery. Fresh external provisioning, hosted authentication, payment journeys and production builds remain separate integration gates. `compose --check` reports reconciliation work; automatic adoption is not implemented.
|
|
121
|
+
|
|
122
|
+
## Add code to your project
|
|
123
|
+
|
|
124
|
+
Run `add` from an existing project:
|
|
44
125
|
|
|
45
126
|
```bash
|
|
46
127
|
pnpm dlx create-next-hydra@latest add owner/repository/drupal-dam
|
|
47
128
|
```
|
|
48
129
|
|
|
49
|
-
The command
|
|
130
|
+
The command inspects the complete registry graph, checks known Provider requirements against installed aliases, and discloses compatibility assumptions it cannot prove without selection state. Inspection and execution retain the same artifacts and recheck project preconditions. ShadCN performs native installation in the existing project; Hydra then reconciles package-local requirements. Configuration-dependent changes need an explicitly configured ShadCN context: the CLI does not invent a workspace-root `components.json` or CSS configuration. Like ShadCN, `--yes` skips confirmation prompts and `--overwrite` authorizes replacing changed targets. `--yes` alone never approves replacing code or dependency versions. Dependency-bearing additions install on every explicit invocation, including retries. Addition has no project lock, receipt or composition snapshot. A native operation or installation failure may leave changes; inspect them before retrying rather than assuming rollback.
|
|
131
|
+
|
|
132
|
+
`add` accepts ordinary registry items and Next Hydra Add-ons. It does not switch Providers or apply Presets. In v1, an Add-on that declares separate binary assets or pnpm patches must be selected in a named workspace or during a new scaffold.
|
|
50
133
|
|
|
51
|
-
|
|
134
|
+
After a successful addition, the CLI prints setup instructions from the installed item and its registry dependencies.
|
|
52
135
|
|
|
53
|
-
## Author a Provider or Add-on
|
|
136
|
+
## Author a Provider, Recipe or Add-on
|
|
137
|
+
|
|
138
|
+
Commerce's registry item depends on the composition recipes `commerce-web`, `commerce-api`, and `commerce-admin`. These wire the complete Commerce package into other applications; they are not independent shopping-feature choices. Auth owns its provider routes and its Commerce identity/webhook recipe. No application profile or separate web shell is required. The planner includes `app-web` automatically; the shared constructor includes only selected applications and their package dependency closure. Unselected source never enters the destination.
|
|
139
|
+
|
|
140
|
+
Recipe describes an assembly unit, not its size: recipes can depend on smaller recipes through `registryDependencies`. A recipe may install files and dependencies, bind module exports into template slots, or combine these. The individual placements are **slot bindings**, not separate recipes. Provider-specific **provisioning recipes**, such as Drupal configuration or Contentstack content blocks, configure external systems in a separate provisioning step. Composition can include their files but never executes them.
|
|
54
141
|
|
|
55
142
|
Keep source in its normal package or application directory and place a `registry.json` beside it. Add that registry file to the root `registry.json` `include` list. A registry containing Selection Definitions uses [`source-registry.json`](./schema/source-registry.json), which applies the complete [`selection-definition.json`](./schema/selection-definition.json) registry-item schema whenever an item contains `meta.nextHydra`. Ordinary registry items continue to use ShadCN's schema.
|
|
56
143
|
|
|
57
144
|
A Selection Definition declares:
|
|
58
145
|
|
|
59
|
-
- its stable ID and whether it is a Provider, Add-on, or Preset;
|
|
60
|
-
- a Provider Slot when it is a Provider;
|
|
146
|
+
- its stable ID and whether it is a Provider, Package, Recipe, Add-on, or Preset;
|
|
147
|
+
- a Provider Slot and one package `binding` when it is a Provider;
|
|
148
|
+
- an optional `binding.sourcePath` for resolving a Provider to its package inside the materialized workspace;
|
|
149
|
+
- `providerDependencies` for packages installed by the selection that consume a Provider Slot;
|
|
61
150
|
- standard ShadCN `registryDependencies` for any other registry items it needs;
|
|
151
|
+
- conditional dependencies for recipes activated by occupied Provider Slots;
|
|
152
|
+
- `providerSlots` requirements on a Package or Recipe, such as Commerce requiring Auth;
|
|
62
153
|
- required and conflicting selection IDs;
|
|
63
|
-
- exact package entries
|
|
64
|
-
- exact pnpm patch entries and their patch-file assets;
|
|
154
|
+
- ordinary exact package entries;
|
|
155
|
+
- exact pnpm patch entries and their patch-file assets;
|
|
156
|
+
- composition templates, named insertion slots, and ordered slot bindings;
|
|
157
|
+
- selection-owned TypeScript aliases needed for composed modules to resolve inside the workspace;
|
|
65
158
|
- setup instructions through the registry item's standard `docs` field.
|
|
66
159
|
|
|
67
160
|
Every copied registry file must have an explicit workspace-root target such as `~/packages/cms-drupal/src/index.ts`. The source `path` remains relative to the colocated registry, so maintainers edit and test canonical Provider code in its normal package or application.
|
|
68
161
|
|
|
69
|
-
When a Provider or Add-on needs to place a file outside its own source directory, keep that source under a colocated `registry/` directory using its final workspace path. For example, `packages/cms-drupal/registry/apps/web/app/api/draft/route.ts` is installed as `~/apps/web/app/api/draft/route.ts`. These files are ordinary ShadCN registry files: ShadCN installs them during scaffolding and
|
|
162
|
+
When a Provider or Add-on needs to place a file outside its own source directory, keep that source under a colocated `registry/` directory using its final workspace path. For example, `packages/cms-drupal/registry/apps/web/app/api/draft/route.ts` is installed as `~/apps/web/app/api/draft/route.ts`. These files are ordinary ShadCN registry files: ShadCN installs them during scaffolding and `add`, while named `compose` copies their canonical sources and may remove or replace unchanged owned targets when the selected stack changes.
|
|
163
|
+
|
|
164
|
+
A composition recipe may instead reference ordinary files already authored in the destination app, as `commerce-web` does for Checkout. Its colocated app registry declares those files, and the owning package depends on that item. This preserves direct source authoring without making duplicate route templates or using unsupported parent-directory registry paths.
|
|
70
165
|
|
|
71
|
-
Run these commands after adding, moving, or removing
|
|
166
|
+
Run these commands after adding, moving, or removing registry-owned files:
|
|
72
167
|
|
|
73
168
|
```bash
|
|
74
169
|
pnpm registry:sync
|
|
@@ -77,7 +172,42 @@ pnpm registry:check
|
|
|
77
172
|
|
|
78
173
|
`registry:sync` regenerates only each registry item's `files` list and its final workspace-root targets. Provider-owned metadata stays in the colocated registry file. Next Hydra first walks the intact `registryDependencies` graph to retain metadata and detect target conflicts, then prepares those exact artifacts and asks ShadCN to install them once from the workspace root.
|
|
79
174
|
|
|
80
|
-
Standard ShadCN `dependencies` and `devDependencies` apply to the workspace root. Use `meta.nextHydra.packages` only when
|
|
175
|
+
Standard ShadCN `dependencies` and `devDependencies` apply to the workspace root. Use `meta.nextHydra.packages` only when an ordinary dependency must be added to a specific workspace package. Stable Provider aliases are derived from the slot and cannot be declared in `packages`.
|
|
176
|
+
|
|
177
|
+
Project creation and named `compose` record those standard dependency fields through the same manifest logic before the final package install, including with `--no-install`. Only selected registry items and their transitive dependencies participate. Bare package names preserve existing requirements; a new bare name uses `latest` until installation resolves it. Explicit versions, tags, and named aliases are preserved, and conflicting explicit requirements fail during preparation. URL or local-path requirements must include a package name (`name@specifier`); unnamed sources cannot be resolved in an install-free plan. `add` continues to use ShadCN's dependency installer.
|
|
178
|
+
|
|
179
|
+
Use `meta.composition.templates` for shared-file structure and `meta.composition.slotBindings` for references to ordinary module exports. This renderer is shared by `compose` and initial scaffolding. Modules remain normal TypeScript/TSX source, and targets have ordinary filenames with no ongoing generation step in scaffolded projects. A selection may declare `typeScriptAliases` for application-level module overrides that must persist in both named and scaffolded workspaces. Both target and alias are catalog-governed. `add` rejects composition recipes and template recomposition because it cannot safely regenerate files you may have edited.
|
|
180
|
+
|
|
181
|
+
Contentstack declares `conditionalDependencies: [{ providers: ["commerce"], items: ["cms-contentstack-commerce"] }]`; Drupal uses `cms-drupal-commerce` in the same way. These `kind: "recipe"` items connect the selected CMS to Commerce core, not to a specific Commerce provider. They install the CMS mapping and `@repo/commerce` dependency automatically when both capabilities are selected, rather than exposing product collection as a selectable Add-on. Registry discovery fetches possible recipes, while planning installs only applicable ones. Contentstack's `recipe/recipes/product-collection.json` remains a feature-specific provisioning recipe: the provisioning command applies it to the base content type and seed entry before importing the stack.
|
|
182
|
+
|
|
183
|
+
A Provider declares its installable package once:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"kind": "provider",
|
|
188
|
+
"slot": "cms",
|
|
189
|
+
"binding": {
|
|
190
|
+
"specifier": "npm:@vendor/cms-provider@^1.0.0"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
An Add-on that installs a package which imports the selected CMS declares the consumer, not a concrete CMS package:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"kind": "add-on",
|
|
200
|
+
"providerDependencies": [
|
|
201
|
+
{
|
|
202
|
+
"cwd": "packages/vendor-search",
|
|
203
|
+
"section": "dependencies",
|
|
204
|
+
"slot": "cms"
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Scaffold and `compose` resolve that dependency to `@repo/cms` using the selected Provider's `binding.specifier`. If the Provider also declares `binding.sourcePath`, they write the exact alias and its `/*` wildcard into every selected consumer's `tsconfig.json`, resolving source inside the materialized project. These aliases are identical in named and scaffolded workspaces. Without `sourcePath`, pnpm's installed alias is the only resolution path and Next Hydra writes no TypeScript path override. Catalog-governed overrides are removed when they are no longer selected; named `compose --check` reports changed or stale physical configuration. `add`, which has no retained selection receipt, copies the exact Provider alias already present in `apps/web/package.json` into each installed consumer.
|
|
81
211
|
|
|
82
212
|
ShadCN reads registry source files as text. For a binary file that must survive byte-for-byte, or a root patch file referenced by `pnpmPatches`, an official or locally included source-registry selection may declare a typed `assets` source and target instead. Separately fetched external selections cannot contribute assets in v1.
|
|
83
213
|
|
|
@@ -85,7 +215,7 @@ ShadCN registry mappings, including private registry URLs and environment-backed
|
|
|
85
215
|
|
|
86
216
|
## Current limits
|
|
87
217
|
|
|
88
|
-
-
|
|
89
|
-
- A scaffolded
|
|
90
|
-
- Composition installs local code and JavaScript dependencies.
|
|
218
|
+
- The official registry requires CMS. Auth is optional; Commerce requires Auth. A source catalog must include the shared `app-web` item.
|
|
219
|
+
- A scaffolded project has no composition receipt and cannot be automatically upgraded or switched later.
|
|
220
|
+
- Composition installs local code and JavaScript dependencies. External service setup runs separately through explicit provider administration commands or manual setup; composition never provisions remote systems.
|
|
91
221
|
- Selection Definitions are declarative and cannot run arbitrary hooks.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Stdio } from "effect";
|
|
2
|
+
import { Command, Prompt } from "effect/unstable/cli";
|
|
3
|
+
import { AdditionConflict } from "./addition.ts";
|
|
4
|
+
import { InvalidComposition } from "./errors.ts";
|
|
5
|
+
import { Workspaces } from "./workspaces.ts";
|
|
6
|
+
export declare const addCommand: (cwd: string) => Command.Command<"add", {
|
|
7
|
+
readonly overwrite: boolean;
|
|
8
|
+
readonly reference: string;
|
|
9
|
+
readonly yes: boolean;
|
|
10
|
+
}, {}, InvalidComposition | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").DependencyInstallationFailed | import("effect/Schema").SchemaError | import("effect/PlatformError").PlatformError | import("./addition.ts").AdditionChanged | AdditionConflict | import("./addition.ts").AdditionFailed | import("effect/Terminal").QuitError, Workspaces | Stdio.Stdio | Prompt.Environment>;
|
|
11
|
+
//# sourceMappingURL=add-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-command.d.ts","sourceRoot":"","sources":["../src/add-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAY,OAAO,EAAQ,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM;;;;+aAmGmC,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Console, Effect, Stdio } from "effect";
|
|
2
|
+
import { Argument, Command, Flag, Prompt } from "effect/unstable/cli";
|
|
3
|
+
import { AdditionConflict } from "./addition.js";
|
|
4
|
+
import { InvalidComposition } from "./errors.js";
|
|
5
|
+
import { Workspaces } from "./workspaces.js";
|
|
6
|
+
export const addCommand = (cwd) => Command.make("add", {
|
|
7
|
+
overwrite: Flag.Boolean("overwrite").pipe(Flag.withAlias("o"), Flag.withDefault(false), Flag.withDescription("Replace changed files and package entries.")),
|
|
8
|
+
reference: Argument.String("reference").pipe(Argument.withDescription("Registry item URL, namespaced reference or local JSON file.")),
|
|
9
|
+
yes: Flag.Boolean("yes").pipe(Flag.withAlias("y"), Flag.withDefault(false), Flag.withDescription("Skip confirmation prompts; does not permit replacement.")),
|
|
10
|
+
}, (options) => Effect.gen(function* () {
|
|
11
|
+
const workspace = yield* (yield* Workspaces).existing({ root: cwd });
|
|
12
|
+
const inspection = yield* workspace.inspectAdd({
|
|
13
|
+
reference: options.reference,
|
|
14
|
+
});
|
|
15
|
+
for (const assumption of inspection.assumptions) {
|
|
16
|
+
yield* Console.warn(assumption);
|
|
17
|
+
}
|
|
18
|
+
if (inspection.environment.length) {
|
|
19
|
+
yield* Console.warn(`Registry environment defaults may be added by ShadCN: ${inspection.environment.join(", ")}`);
|
|
20
|
+
}
|
|
21
|
+
const changes = [
|
|
22
|
+
...inspection.files.map((file) => ({ ...file, label: file.target })),
|
|
23
|
+
...inspection.packages.map((entry) => ({
|
|
24
|
+
...entry,
|
|
25
|
+
label: `${entry.target}: ${entry.section}.${entry.name}`,
|
|
26
|
+
})),
|
|
27
|
+
];
|
|
28
|
+
for (const change of changes) {
|
|
29
|
+
yield* Console.log(`${change.status}: ${change.label}`);
|
|
30
|
+
}
|
|
31
|
+
const conflicts = changes.filter((change) => change.status === "changed");
|
|
32
|
+
let { overwrite } = options;
|
|
33
|
+
if (options.yes) {
|
|
34
|
+
if (conflicts.length && !overwrite) {
|
|
35
|
+
return yield* new AdditionConflict({
|
|
36
|
+
paths: conflicts.map((change) => change.label),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const stdio = yield* Stdio.Stdio;
|
|
42
|
+
if (!(yield* stdio.stdinIsTerminal) ||
|
|
43
|
+
!(yield* stdio.stdoutIsTerminal)) {
|
|
44
|
+
return yield* new InvalidComposition({
|
|
45
|
+
message: "Addition requires confirmation. Use --yes for noninteractive installation and --overwrite only to permit replacements.",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (!overwrite) {
|
|
49
|
+
for (const conflict of conflicts) {
|
|
50
|
+
if (!(yield* Prompt.Confirm({
|
|
51
|
+
initial: false,
|
|
52
|
+
message: `Replace ${conflict.label}?`,
|
|
53
|
+
}))) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
overwrite = conflicts.length > 0;
|
|
58
|
+
}
|
|
59
|
+
if (!(yield* Prompt.Confirm({
|
|
60
|
+
initial: false,
|
|
61
|
+
message: "Install this registry item and its dependencies?",
|
|
62
|
+
}))) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const result = yield* workspace.add({
|
|
67
|
+
expected: inspection.precondition,
|
|
68
|
+
overwrite,
|
|
69
|
+
reference: options.reference,
|
|
70
|
+
});
|
|
71
|
+
yield* Console.log("Registry item installed.");
|
|
72
|
+
for (const instruction of result.instructions) {
|
|
73
|
+
yield* Console.log(`${instruction.item}:\n${instruction.text}`);
|
|
74
|
+
}
|
|
75
|
+
})).pipe(Command.withDescription("Add a registry item to this project."));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Effect, FileSystem, Path, Schema } from "effect";
|
|
2
|
+
import { InvalidComposition } from "./errors.ts";
|
|
3
|
+
import type { PackageRequirement } from "./packages.ts";
|
|
4
|
+
import { Shadcn } from "./shadcn.ts";
|
|
5
|
+
import { WorkspaceDependencies } from "./workspace-dependencies.ts";
|
|
6
|
+
declare const AdditionChanged_base: Schema.Class<AdditionChanged, Schema.TaggedStruct<"AdditionChanged", {}>, import("effect/Cause").YieldableError>;
|
|
7
|
+
export declare class AdditionChanged extends AdditionChanged_base {
|
|
8
|
+
readonly message = "The registry or project changed after inspection. Inspect the addition again before applying it. No installation was started.";
|
|
9
|
+
}
|
|
10
|
+
declare const AdditionConflict_base: Schema.Class<AdditionConflict, Schema.TaggedStruct<"AdditionConflict", {
|
|
11
|
+
readonly paths: Schema.$Array<Schema.String>;
|
|
12
|
+
}>, import("effect/Cause").YieldableError>;
|
|
13
|
+
export declare class AdditionConflict extends AdditionConflict_base {
|
|
14
|
+
get message(): string;
|
|
15
|
+
}
|
|
16
|
+
declare const AdditionFailed_base: Schema.Class<AdditionFailed, Schema.TaggedStruct<"AdditionFailed", {
|
|
17
|
+
readonly diagnostic: Schema.Redacted<Schema.String>;
|
|
18
|
+
readonly directory: Schema.String;
|
|
19
|
+
readonly phase: Schema.Literals<readonly ["registry", "packages"]>;
|
|
20
|
+
}>, import("effect/Cause").YieldableError>;
|
|
21
|
+
export declare class AdditionFailed extends AdditionFailed_base {
|
|
22
|
+
get message(): string;
|
|
23
|
+
}
|
|
24
|
+
export interface AddRequest {
|
|
25
|
+
readonly reference: string;
|
|
26
|
+
readonly overwrite: boolean;
|
|
27
|
+
readonly expected?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface AddInspection {
|
|
30
|
+
readonly assumptions: readonly string[];
|
|
31
|
+
readonly environment: readonly string[];
|
|
32
|
+
readonly files: readonly {
|
|
33
|
+
readonly target: string;
|
|
34
|
+
readonly status: "create" | "identical" | "changed";
|
|
35
|
+
}[];
|
|
36
|
+
readonly packages: readonly (Omit<PackageRequirement, "specifier"> & {
|
|
37
|
+
readonly status: "create" | "identical" | "changed";
|
|
38
|
+
})[];
|
|
39
|
+
readonly precondition: string;
|
|
40
|
+
}
|
|
41
|
+
export declare const existingWorkspace: (root: string) => Effect.Effect<{
|
|
42
|
+
add: (request: AddRequest) => Effect.Effect<{
|
|
43
|
+
directory: string;
|
|
44
|
+
files: {
|
|
45
|
+
readonly target: string;
|
|
46
|
+
readonly status: "create" | "identical" | "changed";
|
|
47
|
+
}[];
|
|
48
|
+
instructions: readonly import("./model.ts").RegistryInstruction[];
|
|
49
|
+
}, InvalidComposition | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").DependencyInstallationFailed | Schema.SchemaError | import("effect/PlatformError").PlatformError | AdditionChanged | AdditionConflict | AdditionFailed, never>;
|
|
50
|
+
inspectAdd: (request: {
|
|
51
|
+
readonly reference: string;
|
|
52
|
+
}) => Effect.Effect<{
|
|
53
|
+
assumptions: string[];
|
|
54
|
+
environment: string[];
|
|
55
|
+
files: {
|
|
56
|
+
readonly target: string;
|
|
57
|
+
readonly status: "create" | "identical" | "changed";
|
|
58
|
+
}[];
|
|
59
|
+
packages: (Omit<PackageRequirement, "specifier"> & {
|
|
60
|
+
readonly status: "create" | "identical" | "changed";
|
|
61
|
+
})[];
|
|
62
|
+
precondition: string;
|
|
63
|
+
}, InvalidComposition | import("./errors.ts").RegistryFailure | Schema.SchemaError | import("effect/PlatformError").PlatformError, never>;
|
|
64
|
+
}, never, FileSystem.FileSystem | Path.Path | Shadcn | WorkspaceDependencies>;
|
|
65
|
+
export type ExistingWorkspace = Effect.Success<ReturnType<typeof existingWorkspace>>;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=addition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addition.d.ts","sourceRoot":"","sources":["../src/addition.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,MAAM,EACN,UAAU,EAEV,IAAI,EAEJ,MAAM,EACP,MAAM,QAAQ,CAAC;AAEhB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;;AAEpE,qBAAa,eAAgB,SAAQ,oBAGpC;IACC,QAAQ,CAAC,OAAO,mIACkH;CACnI;;;;AACD,qBAAa,gBAAiB,SAAQ,qBAGrC;IACC,IAAI,OAAO,WAEV;CACF;;;;;;AACD,qBAAa,cAAe,SAAQ,mBAOnC;IACC,IAAI,OAAO,WAEV;CACF;AACD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AACD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;KACrD,EAAE,CAAC;IACJ,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG;QACnE,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;KACrD,CAAC,EAAE,CAAC;IACL,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAoND,eAAO,MAAM,iBAAiB;;;;6BA3NT,MAAM;6BACN,QAAQ,GAAG,WAAW,GAAG,SAAS;;;;;4BAoZT,MAAM;;;;;6BArZ/B,MAAM;6BACN,QAAQ,GAAG,WAAW,GAAG,SAAS;;;6BAGlC,QAAQ,GAAG,WAAW,GAAG,SAAS;;;;6EAghBrD,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAC5C,UAAU,CAAC,OAAO,iBAAiB,CAAC,CACrC,CAAC"}
|