create-next-hydra 0.3.0 → 0.4.2
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 +126 -27
- 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 -20
- package/schema/selection-definition.json +143 -4
- 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 -484
- package/dist/composition/catalog.d.ts +0 -26
- package/dist/composition/catalog.d.ts.map +0 -1
- package/dist/composition/catalog.js +0 -317
- 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 -65
- 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 -55
- 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 -366
- package/dist/composition/schema.d.ts +0 -294
- package/dist/composition/schema.d.ts.map +0 -1
- package/dist/composition/schema.js +0 -166
- package/dist/composition/types.d.ts +0 -111
- package/dist/composition/types.d.ts.map +0 -1
- package/dist/composition/types.js +0 -6
- package/dist/composition/typescript-paths.d.ts +0 -6
- package/dist/composition/typescript-paths.d.ts.map +0 -1
- package/dist/composition/typescript-paths.js +0 -157
- package/dist/composition/use.d.ts +0 -23
- package/dist/composition/use.d.ts.map +0 -1
- package/dist/composition/use.js +0 -187
- package/dist/composition/workspace.d.ts +0 -10
- package/dist/composition/workspace.d.ts.map +0 -1
- package/dist/composition/workspace.js +0 -210
- package/dist/constants.d.ts +0 -11
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -39
- 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 -54
- package/dist/sanitize.d.ts +0 -10
- package/dist/sanitize.d.ts.map +0 -1
- package/dist/sanitize.js +0 -110
- package/dist/scaffold.d.ts +0 -7
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/scaffold.js +0 -330
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../src/selection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AAEzD,OAAO,KAAK,EACV,kBAAkB,EAClB,wBAAwB,EACzB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAY/B,eAAO,MAAM,eAAe;;;;;CAKlB,CAAC;AAUX,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkFZ,CAAC;AAyMH,eAAO,MAAM,aAAa;;;;;kBA+PksjB,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;oBAAkK,CAAC;yBAAyB,CAAC;sBAAwC,CAAC;mBAAqC,CAAC;4BAA8C,CAAC;sBAAyC,CAAC;;qBAA8D,CAAC;sBAAyG,CAAC;uBAAoD,CAAC;iBAAmC,CAAC;mBAAqC,CAAC;eAAiC,CAAC;eAAkC,CAAC;eAAkC,CAAC;mBAAsC,CAAC;0BAA0B,CAAC;kBAAoC,CAAC;qBAAuC,CAAC;mBAAqC,CAAC;qBAAuC,CAAC;;sBAA+D,CAAC;;sBAAuE,CAAC;uBAAyD,CAAC;;;;;;;;;;;;;;;mBAAwgB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;;;kBAAu3P,CAAC;mBAAuC,CAAC;oBAAwC,CAAC;sBAAwC,CAAC;;;;;kBAAyG,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;kBAA49M,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAtJz7pC,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;kBAoJ+rjB,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;oBAAkK,CAAC;yBAAyB,CAAC;sBAAwC,CAAC;mBAAqC,CAAC;4BAA8C,CAAC;sBAAyC,CAAC;;qBAA8D,CAAC;sBAAyG,CAAC;uBAAoD,CAAC;iBAAmC,CAAC;mBAAqC,CAAC;eAAiC,CAAC;eAAkC,CAAC;eAAkC,CAAC;mBAAsC,CAAC;0BAA0B,CAAC;kBAAoC,CAAC;qBAAuC,CAAC;mBAAqC,CAAC;qBAAuC,CAAC;;sBAA+D,CAAC;;sBAAuE,CAAC;uBAAyD,CAAC;;;;;;;;;;;;;;;mBAAwgB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;;;kBAAu3P,CAAC;mBAAuC,CAAC;oBAAwC,CAAC;sBAAwC,CAAC;;;;;kBAAyG,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;kBAA49M,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA1H17pC,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,UAAU,OAAO,QAAQ,CAAC,IAAI,GAAG,SAAS,EAC1C,WAAW,SAAS,aAQnB,CAAC;AAEJ,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;kBA4G4rjB,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;oBAAkK,CAAC;yBAAyB,CAAC;sBAAwC,CAAC;mBAAqC,CAAC;4BAA8C,CAAC;sBAAyC,CAAC;;qBAA8D,CAAC;sBAAyG,CAAC;uBAAoD,CAAC;iBAAmC,CAAC;mBAAqC,CAAC;eAAiC,CAAC;eAAkC,CAAC;eAAkC,CAAC;mBAAsC,CAAC;0BAA0B,CAAC;kBAAoC,CAAC;qBAAuC,CAAC;mBAAqC,CAAC;qBAAuC,CAAC;;sBAA+D,CAAC;;sBAAuE,CAAC;uBAAyD,CAAC;;;;;;;;;;;;;;;mBAAwgB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;;;kBAAu3P,CAAC;mBAAuC,CAAC;oBAAwC,CAAC;sBAAwC,CAAC;;;;;kBAAyG,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;;;kBAA49M,CAAC;qBAAqB,CAAC;uBAAsD,CAAC;uBAA2C,CAAC;;;;;;;;;;;;;;;;;mBAA0jB,CAAC;;;;mBAAsT,CAAC;kBAAoC,CAAC;;;iBAAyE,CAAC;iBAAmD,CAAC;gBAAkD,CAAC;;;;;;;yBAzSt6pC,MAAM;yBACN,MAAM;wBACP,MAAM;;;;;;;;0EAsSzB,CAAC"}
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { IncompatibleSelection, InvalidComposition } from "./errors.js";
|
|
3
|
+
import { relativeFile } from "./files.js";
|
|
4
|
+
import { Selection, SelectionRequest } from "./model.js";
|
|
5
|
+
import { DependencySection } from "./packages.js";
|
|
6
|
+
const manifestTarget = Effect.fn("Composition.manifestTarget")(function* (cwd) {
|
|
7
|
+
return cwd === "."
|
|
8
|
+
? "package.json"
|
|
9
|
+
: `${yield* relativeFile(cwd)}/package.json`;
|
|
10
|
+
});
|
|
11
|
+
const SlotRequirement = Schema.Literals(["required", "optional", "forbidden"]);
|
|
12
|
+
const ProviderSlot = Schema.Literals(["auth", "cms", "commerce", "search"]);
|
|
13
|
+
export const providerAliases = {
|
|
14
|
+
auth: "@repo/auth",
|
|
15
|
+
cms: "@repo/cms",
|
|
16
|
+
commerce: "@repo/commerce-provider",
|
|
17
|
+
search: "@repo/search-provider",
|
|
18
|
+
};
|
|
19
|
+
const officialReferences = {
|
|
20
|
+
algolia: "next-hydra/search/algolia",
|
|
21
|
+
clerk: "next-hydra/auth/clerk",
|
|
22
|
+
commercetools: "next-hydra/commerce/commercetools",
|
|
23
|
+
contentstack: "next-hydra/cms/contentstack",
|
|
24
|
+
drupal: "next-hydra/cms/drupal",
|
|
25
|
+
standard: "next-hydra/preset/standard",
|
|
26
|
+
workos: "next-hydra/auth/workos",
|
|
27
|
+
};
|
|
28
|
+
const Metadata = Schema.Struct({
|
|
29
|
+
assets: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
30
|
+
source: Schema.NonEmptyString,
|
|
31
|
+
target: Schema.NonEmptyString,
|
|
32
|
+
}))),
|
|
33
|
+
binding: Schema.optionalKey(Schema.Struct({
|
|
34
|
+
sourcePath: Schema.optionalKey(Schema.NonEmptyString),
|
|
35
|
+
specifier: Schema.NonEmptyString,
|
|
36
|
+
})),
|
|
37
|
+
compatibility: Schema.optionalKey(Schema.Struct({
|
|
38
|
+
conflicts: Schema.optionalKey(Schema.Array(Schema.NonEmptyString)),
|
|
39
|
+
requires: Schema.optionalKey(Schema.Array(Schema.NonEmptyString)),
|
|
40
|
+
})),
|
|
41
|
+
conditionalDependencies: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
42
|
+
items: Schema.NonEmptyArray(Schema.NonEmptyString),
|
|
43
|
+
providers: Schema.NonEmptyArray(ProviderSlot),
|
|
44
|
+
}))),
|
|
45
|
+
id: Schema.NonEmptyString,
|
|
46
|
+
kind: Schema.Literals(["provider", "package", "recipe", "add-on", "preset"]),
|
|
47
|
+
packages: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
48
|
+
cwd: Schema.NonEmptyString,
|
|
49
|
+
name: Schema.NonEmptyString,
|
|
50
|
+
section: DependencySection,
|
|
51
|
+
specifier: Schema.NonEmptyString,
|
|
52
|
+
}))),
|
|
53
|
+
pnpmPatches: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
54
|
+
dependency: Schema.NonEmptyString,
|
|
55
|
+
path: Schema.NonEmptyString,
|
|
56
|
+
}))),
|
|
57
|
+
providerDependencies: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
58
|
+
cwd: Schema.NonEmptyString,
|
|
59
|
+
section: DependencySection,
|
|
60
|
+
slot: ProviderSlot,
|
|
61
|
+
}))),
|
|
62
|
+
providerSlots: Schema.optionalKey(Schema.Struct({
|
|
63
|
+
auth: Schema.optionalKey(SlotRequirement),
|
|
64
|
+
cms: Schema.optionalKey(SlotRequirement),
|
|
65
|
+
commerce: Schema.optionalKey(SlotRequirement),
|
|
66
|
+
search: Schema.optionalKey(SlotRequirement),
|
|
67
|
+
})),
|
|
68
|
+
selections: Schema.optionalKey(Schema.Struct({
|
|
69
|
+
addOns: Schema.optionalKey(Schema.Array(Schema.NonEmptyString)),
|
|
70
|
+
providers: Schema.optionalKey(Selection.fields.providers),
|
|
71
|
+
})),
|
|
72
|
+
slot: Schema.optionalKey(ProviderSlot),
|
|
73
|
+
typeScriptAliases: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
74
|
+
alias: Schema.NonEmptyString,
|
|
75
|
+
cwd: Schema.NonEmptyString,
|
|
76
|
+
sourcePath: Schema.NonEmptyString,
|
|
77
|
+
}))),
|
|
78
|
+
});
|
|
79
|
+
const validateProviderRequirements = Effect.fn("Composition.validateProviderRequirements")(function* (metadata, selection) {
|
|
80
|
+
for (const slot of ["auth", "cms", "commerce", "search"]) {
|
|
81
|
+
const requirement = metadata.providerSlots?.[slot];
|
|
82
|
+
const present = selection.providers[slot] !== undefined;
|
|
83
|
+
if ((requirement === "required" && !present) ||
|
|
84
|
+
(requirement === "forbidden" && present)) {
|
|
85
|
+
return yield* new InvalidComposition({
|
|
86
|
+
message: `${metadata.id} ${requirement === "required" ? "requires" : "forbids"} ${slot === "auth" ? "an" : "a"} ${slot} provider`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const resolvePackageBindings = Effect.fn("Composition.resolvePackageBindings")(function* (metadataByName, references, selectedItems, selection) {
|
|
92
|
+
const ownedRequirements = [];
|
|
93
|
+
const ownedAliases = [];
|
|
94
|
+
for (const metadata of metadataByName.values()) {
|
|
95
|
+
for (const alias of metadata.typeScriptAliases ?? []) {
|
|
96
|
+
ownedAliases.push({
|
|
97
|
+
alias: alias.alias,
|
|
98
|
+
cwd: alias.cwd === "." ? "." : yield* relativeFile(alias.cwd),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
for (const requirement of metadata.packages ?? []) {
|
|
102
|
+
ownedRequirements.push({
|
|
103
|
+
name: requirement.name,
|
|
104
|
+
section: requirement.section,
|
|
105
|
+
target: yield* manifestTarget(requirement.cwd),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
for (const dependency of metadata.providerDependencies ?? []) {
|
|
109
|
+
ownedAliases.push({
|
|
110
|
+
alias: providerAliases[dependency.slot],
|
|
111
|
+
cwd: dependency.cwd === "." ? "." : yield* relativeFile(dependency.cwd),
|
|
112
|
+
});
|
|
113
|
+
ownedRequirements.push({
|
|
114
|
+
name: providerAliases[dependency.slot],
|
|
115
|
+
section: dependency.section,
|
|
116
|
+
target: yield* manifestTarget(dependency.cwd),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const requirements = [];
|
|
121
|
+
const aliases = [];
|
|
122
|
+
for (const item of selectedItems) {
|
|
123
|
+
const metadata = metadataByName.get(item.name);
|
|
124
|
+
if (metadata) {
|
|
125
|
+
yield* validateProviderRequirements(metadata, selection);
|
|
126
|
+
}
|
|
127
|
+
for (const alias of metadata?.typeScriptAliases ?? []) {
|
|
128
|
+
aliases.push({
|
|
129
|
+
alias: alias.alias,
|
|
130
|
+
cwd: alias.cwd === "." ? "." : yield* relativeFile(alias.cwd),
|
|
131
|
+
sourcePath: yield* relativeFile(alias.sourcePath),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
for (const requirement of metadata?.packages ?? []) {
|
|
135
|
+
requirements.push({
|
|
136
|
+
name: requirement.name,
|
|
137
|
+
section: requirement.section,
|
|
138
|
+
specifier: requirement.specifier,
|
|
139
|
+
target: yield* manifestTarget(requirement.cwd),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
for (const dependency of metadata?.providerDependencies ?? []) {
|
|
143
|
+
const reference = selection.providers[dependency.slot];
|
|
144
|
+
const binding = metadataByName.get(references.get(reference ?? "") ?? "")?.binding;
|
|
145
|
+
if (!binding) {
|
|
146
|
+
return yield* new InvalidComposition({
|
|
147
|
+
message: `${metadata?.id} needs a ${dependency.slot} provider binding`,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
requirements.push({
|
|
151
|
+
name: providerAliases[dependency.slot],
|
|
152
|
+
section: dependency.section,
|
|
153
|
+
specifier: binding.specifier,
|
|
154
|
+
target: yield* manifestTarget(dependency.cwd),
|
|
155
|
+
});
|
|
156
|
+
if (binding.sourcePath) {
|
|
157
|
+
aliases.push({
|
|
158
|
+
alias: providerAliases[dependency.slot],
|
|
159
|
+
cwd: dependency.cwd === "."
|
|
160
|
+
? "."
|
|
161
|
+
: yield* relativeFile(dependency.cwd),
|
|
162
|
+
sourcePath: yield* relativeFile(binding.sourcePath),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const uniqueAliases = new Map();
|
|
168
|
+
for (const alias of aliases) {
|
|
169
|
+
const key = `${alias.cwd}\0${alias.alias}`;
|
|
170
|
+
const previous = uniqueAliases.get(key);
|
|
171
|
+
if (previous && previous.sourcePath !== alias.sourcePath) {
|
|
172
|
+
return yield* new InvalidComposition({
|
|
173
|
+
message: `${alias.cwd} maps ${alias.alias} to both ${previous.sourcePath} and ${alias.sourcePath}`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
uniqueAliases.set(key, alias);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
aliases: [...uniqueAliases.values()],
|
|
180
|
+
ownedAliases,
|
|
181
|
+
ownedRequirements,
|
|
182
|
+
requirements,
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
const validateCompatibility = Effect.fn("Composition.validateCompatibility")(function* (metadataByName, selectedItems) {
|
|
186
|
+
const selectedIds = new Set(selectedItems.flatMap((item) => {
|
|
187
|
+
const metadata = metadataByName.get(item.name);
|
|
188
|
+
return metadata ? [metadata.id] : [];
|
|
189
|
+
}));
|
|
190
|
+
for (const item of selectedItems) {
|
|
191
|
+
const metadata = metadataByName.get(item.name);
|
|
192
|
+
const missing = (metadata?.compatibility?.requires ?? []).filter((id) => !selectedIds.has(id));
|
|
193
|
+
const conflicts = (metadata?.compatibility?.conflicts ?? []).filter((id) => selectedIds.has(id));
|
|
194
|
+
if (metadata && (missing.length || conflicts.length)) {
|
|
195
|
+
return yield* new IncompatibleSelection({
|
|
196
|
+
conflicts,
|
|
197
|
+
missing,
|
|
198
|
+
selection: metadata.id,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
const resolveAssets = Effect.fn("Composition.resolveAssets")(function* (metadataByName, selected) {
|
|
204
|
+
const assets = [];
|
|
205
|
+
const patches = new Map();
|
|
206
|
+
const ownedAssetTargets = new Set();
|
|
207
|
+
for (const [name, metadata] of metadataByName) {
|
|
208
|
+
for (const asset of metadata.assets ?? []) {
|
|
209
|
+
const target = yield* relativeFile(asset.target);
|
|
210
|
+
ownedAssetTargets.add(target);
|
|
211
|
+
if (selected.has(name)) {
|
|
212
|
+
assets.push({
|
|
213
|
+
owner: name,
|
|
214
|
+
source: yield* relativeFile(asset.source),
|
|
215
|
+
target,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (selected.has(name)) {
|
|
220
|
+
for (const patch of metadata.pnpmPatches ?? []) {
|
|
221
|
+
const target = yield* relativeFile(patch.path);
|
|
222
|
+
const previous = patches.get(patch.dependency);
|
|
223
|
+
if (previous && previous !== target) {
|
|
224
|
+
return yield* new InvalidComposition({
|
|
225
|
+
message: `Conflicting patches for ${patch.dependency}: ${previous}, ${target}`,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
patches.set(patch.dependency, target);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const assetTargets = new Set(assets.map((asset) => asset.target));
|
|
233
|
+
for (const [dependency, target] of patches) {
|
|
234
|
+
if (!assetTargets.has(target)) {
|
|
235
|
+
return yield* new InvalidComposition({
|
|
236
|
+
message: `${dependency} references ${target}, which is not a selected asset`,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { assets, ownedAssetTargets, patches };
|
|
241
|
+
});
|
|
242
|
+
export const registryIndex = Effect.fn("Composition.registryIndex")(function* (registry, acquiredReferences = new Map()) {
|
|
243
|
+
const items = new Map(registry.items.map((item) => [item.name, item]));
|
|
244
|
+
if (items.size !== registry.items.length) {
|
|
245
|
+
return yield* new InvalidComposition({
|
|
246
|
+
message: "Registry item names must be unique.",
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
const references = new Map([
|
|
250
|
+
...registry.items.map((item) => [item.name, item.name]),
|
|
251
|
+
...acquiredReferences,
|
|
252
|
+
]);
|
|
253
|
+
const repository = /^https:\/\/github\.com\/(?<repository>[^/]+\/[^/]+?)(?:\.git)?\/?$/u.exec(registry.homepage ?? "")?.groups?.repository;
|
|
254
|
+
if (repository) {
|
|
255
|
+
for (const item of registry.items) {
|
|
256
|
+
references.set(`${repository}/${item.name}`, item.name);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const metadataByName = new Map();
|
|
260
|
+
for (const item of registry.items) {
|
|
261
|
+
if (item.meta?.nextHydra !== undefined) {
|
|
262
|
+
const metadata = yield* Schema.decodeUnknownEffect(Metadata)(item.meta.nextHydra, { onExcessProperty: "error" }).pipe(Effect.mapError(() => new InvalidComposition({
|
|
263
|
+
message: `Unsupported or invalid selection metadata: ${item.name}`,
|
|
264
|
+
})));
|
|
265
|
+
if (metadata.kind !== "provider" && (metadata.slot || metadata.binding)) {
|
|
266
|
+
return yield* new InvalidComposition({
|
|
267
|
+
message: `${metadata.id}: only providers may declare a slot or binding`,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (metadata.kind === "provider" &&
|
|
271
|
+
(!metadata.slot || !metadata.binding)) {
|
|
272
|
+
return yield* new InvalidComposition({
|
|
273
|
+
message: `${metadata.id}: a provider requires both a slot and binding`,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
if ((metadata.kind === "preset") !==
|
|
277
|
+
(metadata.selections !== undefined)) {
|
|
278
|
+
return yield* new InvalidComposition({
|
|
279
|
+
message: `${metadata.id}: selections belong to presets and are required for them`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
if (metadata.kind === "preset" &&
|
|
283
|
+
(metadata.providerDependencies?.length ?? 0) > 0) {
|
|
284
|
+
return yield* new InvalidComposition({
|
|
285
|
+
message: `${metadata.id}: a preset cannot declare provider dependencies`,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
for (const requirement of metadata.packages ?? []) {
|
|
289
|
+
if (Object.values(providerAliases).some((alias) => alias === requirement.name)) {
|
|
290
|
+
return yield* new InvalidComposition({
|
|
291
|
+
message: `${requirement.name} must be declared through providerDependencies`,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (references.has(metadata.id) &&
|
|
296
|
+
references.get(metadata.id) !== item.name) {
|
|
297
|
+
return yield* new InvalidComposition({
|
|
298
|
+
message: `Duplicate selection ID: ${metadata.id}`,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
references.set(metadata.id, item.name);
|
|
302
|
+
metadataByName.set(item.name, metadata);
|
|
303
|
+
if (metadata.providerSlots &&
|
|
304
|
+
metadata.kind !== "package" &&
|
|
305
|
+
metadata.kind !== "recipe") {
|
|
306
|
+
return yield* new InvalidComposition({
|
|
307
|
+
message: `${metadata.id} must be a package or recipe to declare provider requirements`,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const [alias, id] of Object.entries(officialReferences)) {
|
|
313
|
+
const name = references.get(id);
|
|
314
|
+
if (name) {
|
|
315
|
+
references.set(alias, name);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { items, metadataByName, references };
|
|
319
|
+
});
|
|
320
|
+
export const resolveSelection = Effect.fn("Composition.resolveSelection")(function* (index, request) {
|
|
321
|
+
const decoded = yield* Schema.decodeEffect(SelectionRequest)(request, {
|
|
322
|
+
onExcessProperty: "error",
|
|
323
|
+
});
|
|
324
|
+
if (!("preset" in decoded)) {
|
|
325
|
+
return decoded;
|
|
326
|
+
}
|
|
327
|
+
const metadata = index.metadataByName.get(index.references.get(decoded.preset) ?? "");
|
|
328
|
+
if (metadata?.kind !== "preset" || !metadata.selections) {
|
|
329
|
+
return yield* new InvalidComposition({
|
|
330
|
+
message: `${decoded.preset} is not a preset`,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
addOns: [
|
|
335
|
+
...new Set([...(metadata.selections.addOns ?? []), ...decoded.addOns]),
|
|
336
|
+
],
|
|
337
|
+
providers: metadata.selections.providers ?? {},
|
|
338
|
+
};
|
|
339
|
+
});
|
|
340
|
+
export const selectedConditionalDependencies = (metadata, selection) => (metadata?.conditionalDependencies ?? []).flatMap((dependency) => dependency.providers.every((slot) => selection.providers[slot] !== undefined)
|
|
341
|
+
? dependency.items
|
|
342
|
+
: []);
|
|
343
|
+
export const selectRegistryItems = Effect.fn("Composition.selectRegistryItems")(function* (registry, request, acquiredReferences = new Map()) {
|
|
344
|
+
const { items, metadataByName, references } = yield* registryIndex(registry, acquiredReferences);
|
|
345
|
+
const selection = yield* resolveSelection({ items, metadataByName, references }, request);
|
|
346
|
+
for (const [slot, reference] of Object.entries(selection.providers)) {
|
|
347
|
+
const metadata = metadataByName.get(references.get(reference) ?? "");
|
|
348
|
+
if (metadata?.kind !== "provider" ||
|
|
349
|
+
metadata.slot !== slot ||
|
|
350
|
+
!metadata.binding) {
|
|
351
|
+
return yield* new InvalidComposition({
|
|
352
|
+
message: `${reference} is not a ${slot} provider`,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
for (const reference of selection.addOns) {
|
|
357
|
+
const metadata = metadataByName.get(references.get(reference) ?? "");
|
|
358
|
+
if (metadata?.kind !== "add-on") {
|
|
359
|
+
return yield* new InvalidComposition({
|
|
360
|
+
message: `${reference} is not an add-on`,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (!references.has("app-web")) {
|
|
365
|
+
return yield* new InvalidComposition({
|
|
366
|
+
message: "The source registry must include the shared app-web application",
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
const pending = [
|
|
370
|
+
"app-web",
|
|
371
|
+
...Object.values(selection.providers),
|
|
372
|
+
...selection.addOns,
|
|
373
|
+
];
|
|
374
|
+
const selected = new Set();
|
|
375
|
+
const selectedItems = [];
|
|
376
|
+
while (pending.length > 0) {
|
|
377
|
+
const reference = pending.pop();
|
|
378
|
+
if (reference === undefined) {
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
const name = references.get(reference);
|
|
382
|
+
if (!name) {
|
|
383
|
+
return yield* new InvalidComposition({
|
|
384
|
+
message: `Unknown registry selection: ${reference}`,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (selected.has(name)) {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
selected.add(name);
|
|
391
|
+
const item = items.get(name);
|
|
392
|
+
if (!item) {
|
|
393
|
+
return yield* new InvalidComposition({
|
|
394
|
+
message: `Missing registry item: ${name}`,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
selectedItems.push(item);
|
|
398
|
+
pending.push(...(item.registryDependencies ?? []));
|
|
399
|
+
const metadata = metadataByName.get(name);
|
|
400
|
+
if (metadata?.kind === "preset") {
|
|
401
|
+
return yield* new InvalidComposition({
|
|
402
|
+
message: `${metadata.id} is a preset, not a materializable selection; resolve its selections first`,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
for (const recipeReference of selectedConditionalDependencies(metadata, selection)) {
|
|
406
|
+
const target = metadataByName.get(references.get(recipeReference) ?? "");
|
|
407
|
+
if (target?.kind !== "recipe" && target?.kind !== "package") {
|
|
408
|
+
return yield* new InvalidComposition({
|
|
409
|
+
message: `${recipeReference} must be a package or composition recipe`,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
pending.push(recipeReference);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
yield* validateCompatibility(metadataByName, selectedItems);
|
|
416
|
+
const bindings = yield* resolvePackageBindings(metadataByName, references, selectedItems, selection);
|
|
417
|
+
const assets = yield* resolveAssets(metadataByName, selected);
|
|
418
|
+
return {
|
|
419
|
+
...bindings,
|
|
420
|
+
...assets,
|
|
421
|
+
references,
|
|
422
|
+
selectedItems,
|
|
423
|
+
};
|
|
424
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const Request: Schema.Struct<{
|
|
3
|
+
readonly application: Schema.String;
|
|
4
|
+
readonly entries: Schema.$Array<Schema.String>;
|
|
5
|
+
readonly overwrite: Schema.Boolean;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const Outcome: Schema.Union<readonly [Schema.TaggedStruct<"Success", {}>, Schema.TaggedStruct<"RegistryFailure", {
|
|
8
|
+
readonly diagnostic: Schema.String;
|
|
9
|
+
}>, Schema.TaggedStruct<"WorkerDefect", {
|
|
10
|
+
readonly diagnostic: Schema.String;
|
|
11
|
+
}>]>;
|
|
12
|
+
export declare const RequestJson: Schema.fromJsonString<Schema.Struct<{
|
|
13
|
+
readonly application: Schema.String;
|
|
14
|
+
readonly entries: Schema.$Array<Schema.String>;
|
|
15
|
+
readonly overwrite: Schema.Boolean;
|
|
16
|
+
}>>;
|
|
17
|
+
export declare const OutcomeJson: Schema.fromJsonString<Schema.Union<readonly [Schema.TaggedStruct<"Success", {}>, Schema.TaggedStruct<"RegistryFailure", {
|
|
18
|
+
readonly diagnostic: Schema.String;
|
|
19
|
+
}>, Schema.TaggedStruct<"WorkerDefect", {
|
|
20
|
+
readonly diagnostic: Schema.String;
|
|
21
|
+
}>]>>;
|
|
22
|
+
//# sourceMappingURL=shadcn-protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadcn-protocol.d.ts","sourceRoot":"","sources":["../src/shadcn-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,eAAO,MAAM,OAAO;;;;EAIlB,CAAC;AACH,eAAO,MAAM,OAAO;;;;IAIlB,CAAC;AACH,eAAO,MAAM,WAAW;;;;GAAiC,CAAC;AAC1D,eAAO,MAAM,WAAW;;;;KAAiC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export const Request = Schema.Struct({
|
|
3
|
+
application: Schema.String,
|
|
4
|
+
entries: Schema.Array(Schema.String),
|
|
5
|
+
overwrite: Schema.Boolean,
|
|
6
|
+
});
|
|
7
|
+
export const Outcome = Schema.Union([
|
|
8
|
+
Schema.TaggedStruct("Success", {}),
|
|
9
|
+
Schema.TaggedStruct("RegistryFailure", { diagnostic: Schema.String }),
|
|
10
|
+
Schema.TaggedStruct("WorkerDefect", { diagnostic: Schema.String }),
|
|
11
|
+
]);
|
|
12
|
+
export const RequestJson = Schema.fromJsonString(Request);
|
|
13
|
+
export const OutcomeJson = Schema.fromJsonString(Outcome);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadcn-worker.d.ts","sourceRoot":"","sources":["../src/shadcn-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
2
|
+
import { Cause, Effect, FileSystem, Schema } from "effect";
|
|
3
|
+
import { addRegistryItems } from "shadcn/registry";
|
|
4
|
+
import { OutcomeJson, RequestJson } from "./shadcn-protocol.js";
|
|
5
|
+
const main = Effect.gen(function* () {
|
|
6
|
+
const fs = yield* FileSystem.FileSystem;
|
|
7
|
+
const [requestPath, resultPath] = process.argv.slice(2);
|
|
8
|
+
if (!requestPath || !resultPath) {
|
|
9
|
+
return yield* Effect.die(new Error("Missing worker control paths"));
|
|
10
|
+
}
|
|
11
|
+
const result = yield* Effect.gen(function* () {
|
|
12
|
+
const request = yield* fs
|
|
13
|
+
.readFileString(requestPath)
|
|
14
|
+
.pipe(Effect.flatMap(Schema.decodeEffect(RequestJson)));
|
|
15
|
+
return yield* Effect.tryPromise({
|
|
16
|
+
catch: (error) => error instanceof Error
|
|
17
|
+
? error.message.slice(0, 8192)
|
|
18
|
+
: "Registry operation failed",
|
|
19
|
+
try: async () => {
|
|
20
|
+
await addRegistryItems([...request.entries], {
|
|
21
|
+
config: {},
|
|
22
|
+
cwd: request.application,
|
|
23
|
+
overwrite: request.overwrite,
|
|
24
|
+
silent: true,
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
}).pipe(Effect.match({
|
|
28
|
+
onFailure: (diagnostic) => ({
|
|
29
|
+
_tag: "RegistryFailure",
|
|
30
|
+
diagnostic,
|
|
31
|
+
}),
|
|
32
|
+
onSuccess: () => ({ _tag: "Success" }),
|
|
33
|
+
}));
|
|
34
|
+
}).pipe(Effect.catchCause((cause) => Cause.hasInterrupts(cause)
|
|
35
|
+
? Effect.failCause(cause)
|
|
36
|
+
: Effect.succeed({
|
|
37
|
+
_tag: "WorkerDefect",
|
|
38
|
+
diagnostic: Cause.pretty(cause).slice(0, 8192),
|
|
39
|
+
})));
|
|
40
|
+
const encoded = yield* Schema.encodeEffect(OutcomeJson)(result);
|
|
41
|
+
yield* fs.writeFileString(resultPath, encoded, { mode: 0o600 });
|
|
42
|
+
});
|
|
43
|
+
NodeRuntime.runMain(main.pipe(Effect.provide(NodeServices.layer)));
|
package/dist/shadcn.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context, Effect, FileSystem, Layer, Path, Schema } from "effect";
|
|
2
|
+
import type { PlatformError } from "effect";
|
|
3
|
+
import { ChildProcessSpawner } from "effect/unstable/process";
|
|
4
|
+
import { getRegistryItems, loadRegistry, loadRegistryItem } from "shadcn/registry";
|
|
5
|
+
import type { RegistryItem } from "shadcn/schema";
|
|
6
|
+
import { RegistryFailure, RegistryWorkerFailure } from "./errors.ts";
|
|
7
|
+
import type { RegistryInstallation } from "./staging.ts";
|
|
8
|
+
type LoadOptions = Parameters<typeof loadRegistry>[0];
|
|
9
|
+
export type RegistryCatalog = Omit<Awaited<ReturnType<typeof loadRegistry>>, "items"> & {
|
|
10
|
+
readonly items: readonly RegistryItem[];
|
|
11
|
+
};
|
|
12
|
+
declare const Shadcn_base: Context.ServiceClass<Shadcn, "create-next-hydra/Shadcn", {
|
|
13
|
+
readonly getRegistryItems: (references: readonly string[], cwd: string) => Effect.Effect<Awaited<ReturnType<typeof getRegistryItems>>, RegistryFailure>;
|
|
14
|
+
readonly loadRegistry: (options: LoadOptions) => Effect.Effect<Awaited<ReturnType<typeof loadRegistry>>, RegistryFailure>;
|
|
15
|
+
readonly loadRegistryItem: (name: string, options: LoadOptions) => Effect.Effect<Awaited<ReturnType<typeof loadRegistryItem>>, RegistryFailure>;
|
|
16
|
+
readonly install: (staging: RegistryInstallation, entries: readonly string[], overwrite?: boolean) => Effect.Effect<void, RegistryFailure | RegistryWorkerFailure | PlatformError.PlatformError | Schema.SchemaError>;
|
|
17
|
+
}>;
|
|
18
|
+
export declare class Shadcn extends Shadcn_base {
|
|
19
|
+
static layer: (worker?: import("url").URL) => Layer.Layer<Shadcn, never, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=shadcn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadcn.d.ts","sourceRoot":"","sources":["../src/shadcn.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,OAAO,EACP,MAAM,EACN,UAAU,EACV,KAAK,EACL,IAAI,EAEJ,MAAM,EACP,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAEL,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,EACxC,OAAO,CACR,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;;+BAKjB,CACzB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,GAAG,EAAE,MAAM,KACR,MAAM,CAAC,MAAM,CAChB,OAAO,CAAC,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,EAC5C,eAAe,CAChB;2BACsB,CACrB,OAAO,EAAE,WAAW,KACjB,MAAM,CAAC,MAAM,CAChB,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,EACxC,eAAe,CAChB;+BAC0B,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,KACjB,MAAM,CAAC,MAAM,CAChB,OAAO,CAAC,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,EAC5C,eAAe,CAChB;sBACiB,CAChB,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,CAAC,EAAE,OAAO,KAChB,MAAM,CAAC,MAAM,CAChB,IAAI,EACF,eAAe,GACf,qBAAqB,GACrB,aAAa,CAAC,aAAa,GAC3B,MAAM,CAAC,WAAW,CACrB;;AAjCL,qBAAa,MAAO,SAAQ,WAmCG;IAC7B,MAAM,CAAC,KAAK,GAAI,0BAAqD,6GAwJjE;CACL"}
|
package/dist/shadcn.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { Context, Effect, FileSystem, Layer, Path, Redacted, Schema, } from "effect";
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
4
|
+
import { getRegistriesConfig, getRegistryItems, loadRegistry, loadRegistryItem, } from "shadcn/registry";
|
|
5
|
+
import { RegistryFailure, RegistryWorkerFailure } from "./errors.js";
|
|
6
|
+
import { confirmStopped, groupExists } from "./process-group.js";
|
|
7
|
+
import { OutcomeJson, RequestJson } from "./shadcn-protocol.js";
|
|
8
|
+
import { stopped, writing } from "./staging.js";
|
|
9
|
+
export class Shadcn extends Context.Service()("create-next-hydra/Shadcn") {
|
|
10
|
+
static layer = (worker = new URL("shadcn-worker.js", import.meta.url)) => Layer.effect(Shadcn, Effect.gen(function* () {
|
|
11
|
+
const fs = yield* FileSystem.FileSystem;
|
|
12
|
+
const path = yield* Path.Path;
|
|
13
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
14
|
+
return Shadcn.of({
|
|
15
|
+
getRegistryItems: (references, cwd) => Effect.tryPromise({
|
|
16
|
+
catch: (error) => new RegistryFailure({
|
|
17
|
+
diagnostic: Redacted.make(error instanceof Error
|
|
18
|
+
? error.message
|
|
19
|
+
: "Registry acquisition failed"),
|
|
20
|
+
operation: "acquire registry artifacts",
|
|
21
|
+
}),
|
|
22
|
+
try: async () => await getRegistryItems([...references], {
|
|
23
|
+
config: await getRegistriesConfig(cwd),
|
|
24
|
+
}),
|
|
25
|
+
}).pipe(Effect.uninterruptible),
|
|
26
|
+
install: Effect.fn("Shadcn.install")(function* (staging, entries, overwrite = true) {
|
|
27
|
+
if (process.platform === "win32") {
|
|
28
|
+
return yield* new RegistryWorkerFailure({ phase: "launch" });
|
|
29
|
+
}
|
|
30
|
+
const requestPath = path.join(staging.control, "request.json");
|
|
31
|
+
const resultPath = path.join(staging.control, "result.json");
|
|
32
|
+
const request = yield* Schema.encodeEffect(RequestJson)({
|
|
33
|
+
application: staging.application,
|
|
34
|
+
entries,
|
|
35
|
+
overwrite,
|
|
36
|
+
});
|
|
37
|
+
yield* fs
|
|
38
|
+
.writeFileString(requestPath, request, { mode: 0o600 })
|
|
39
|
+
.pipe(Effect.uninterruptible);
|
|
40
|
+
yield* Effect.scoped(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
41
|
+
yield* writing(staging);
|
|
42
|
+
const handle = yield* spawner
|
|
43
|
+
.spawn(ChildProcess.make(process.execPath, [fileURLToPath(worker), requestPath, resultPath], {
|
|
44
|
+
cwd: staging.application,
|
|
45
|
+
forceKillAfter: "100 millis",
|
|
46
|
+
stderr: "ignore",
|
|
47
|
+
stdin: "ignore",
|
|
48
|
+
stdout: "ignore",
|
|
49
|
+
}))
|
|
50
|
+
.pipe(Effect.tapError(() => stopped(staging)), Effect.mapError(() => new RegistryWorkerFailure({ phase: "launch" })));
|
|
51
|
+
yield* restore(Effect.gen(function* () {
|
|
52
|
+
const code = yield* handle.exitCode.pipe(Effect.mapError(() => new RegistryWorkerFailure({ phase: "exit" })));
|
|
53
|
+
if (code !== 0 ||
|
|
54
|
+
(yield* groupExists(handle.pid).pipe(Effect.mapError(() => new RegistryWorkerFailure({ phase: "stop" }))))) {
|
|
55
|
+
return yield* new RegistryWorkerFailure({
|
|
56
|
+
phase: "exit",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
})).pipe(Effect.onExit(() => confirmStopped(handle).pipe(Effect.mapError(() => new RegistryWorkerFailure({ phase: "stop" })), Effect.andThen(stopped(staging)),
|
|
60
|
+
// Prevent an unbounded second termination attempt by the process scope.
|
|
61
|
+
Effect.onExit(() => handle.unref.pipe(Effect.asVoid)))));
|
|
62
|
+
})));
|
|
63
|
+
if ((yield* fs.stat(resultPath)).size > 65_536) {
|
|
64
|
+
return yield* new RegistryWorkerFailure({ phase: "protocol" });
|
|
65
|
+
}
|
|
66
|
+
const outcome = yield* fs.readFileString(resultPath).pipe(Effect.flatMap(Schema.decodeEffect(OutcomeJson)), Effect.mapError(() => new RegistryWorkerFailure({ phase: "protocol" })));
|
|
67
|
+
if (outcome._tag === "RegistryFailure") {
|
|
68
|
+
return yield* new RegistryFailure({
|
|
69
|
+
diagnostic: Redacted.make(outcome.diagnostic),
|
|
70
|
+
operation: "install registry items",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (outcome._tag === "WorkerDefect") {
|
|
74
|
+
return yield* Effect.die({
|
|
75
|
+
diagnostic: Redacted.make(outcome.diagnostic),
|
|
76
|
+
message: "Registry worker defect",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
// The upstream read API has no cancellation signal. Join before releasing inputs.
|
|
81
|
+
loadRegistry: (options) => Effect.tryPromise({
|
|
82
|
+
catch: (error) => new RegistryFailure({
|
|
83
|
+
diagnostic: Redacted.make(error instanceof Error
|
|
84
|
+
? error.message
|
|
85
|
+
: "Registry loading failed"),
|
|
86
|
+
operation: "load registry",
|
|
87
|
+
}),
|
|
88
|
+
try: async () => await loadRegistry(options),
|
|
89
|
+
}).pipe(Effect.uninterruptible),
|
|
90
|
+
loadRegistryItem: (name, options) => Effect.tryPromise({
|
|
91
|
+
catch: (error) => new RegistryFailure({
|
|
92
|
+
diagnostic: Redacted.make(error instanceof Error
|
|
93
|
+
? error.message
|
|
94
|
+
: "Registry hydration failed"),
|
|
95
|
+
operation: "hydrate registry item",
|
|
96
|
+
}),
|
|
97
|
+
try: async () => await loadRegistryItem(name, options),
|
|
98
|
+
}).pipe(Effect.uninterruptible),
|
|
99
|
+
});
|
|
100
|
+
}));
|
|
101
|
+
}
|