@alchemy.run/pkg 0.0.0-placeholder → 2.0.0-beta.79

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 (70) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +5 -0
  3. package/README.md +117 -0
  4. package/dist/Manifest.d.ts +107 -0
  5. package/dist/Manifest.d.ts.map +1 -0
  6. package/dist/Manifest.js +58 -0
  7. package/dist/Manifest.js.map +1 -0
  8. package/dist/Protocol.d.ts +186 -0
  9. package/dist/Protocol.d.ts.map +1 -0
  10. package/dist/Protocol.js +115 -0
  11. package/dist/Protocol.js.map +1 -0
  12. package/dist/Registry/Bindings.d.ts +134 -0
  13. package/dist/Registry/Bindings.d.ts.map +1 -0
  14. package/dist/Registry/Bindings.js +92 -0
  15. package/dist/Registry/Bindings.js.map +1 -0
  16. package/dist/Registry/GitHub.d.ts +96 -0
  17. package/dist/Registry/GitHub.d.ts.map +1 -0
  18. package/dist/Registry/GitHub.js +226 -0
  19. package/dist/Registry/GitHub.js.map +1 -0
  20. package/dist/Registry/Handler.d.ts +53 -0
  21. package/dist/Registry/Handler.d.ts.map +1 -0
  22. package/dist/Registry/Handler.js +375 -0
  23. package/dist/Registry/Handler.js.map +1 -0
  24. package/dist/Registry/KVCache.d.ts +24 -0
  25. package/dist/Registry/KVCache.d.ts.map +1 -0
  26. package/dist/Registry/KVCache.js +42 -0
  27. package/dist/Registry/KVCache.js.map +1 -0
  28. package/dist/Registry/Sweep.d.ts +12 -0
  29. package/dist/Registry/Sweep.d.ts.map +1 -0
  30. package/dist/Registry/Sweep.js +69 -0
  31. package/dist/Registry/Sweep.js.map +1 -0
  32. package/dist/Registry/Tags.d.ts +49 -0
  33. package/dist/Registry/Tags.d.ts.map +1 -0
  34. package/dist/Registry/Tags.js +80 -0
  35. package/dist/Registry/Tags.js.map +1 -0
  36. package/dist/Registry.d.ts +378 -0
  37. package/dist/Registry.d.ts.map +1 -0
  38. package/dist/Registry.js +119 -0
  39. package/dist/Registry.js.map +1 -0
  40. package/dist/cli/bin.d.ts +18 -0
  41. package/dist/cli/bin.d.ts.map +1 -0
  42. package/dist/cli/bin.js +33 -0
  43. package/dist/cli/bin.js.map +1 -0
  44. package/dist/cli/pack.d.ts +169 -0
  45. package/dist/cli/pack.d.ts.map +1 -0
  46. package/dist/cli/pack.js +447 -0
  47. package/dist/cli/pack.js.map +1 -0
  48. package/dist/cli/publish.d.ts +33 -0
  49. package/dist/cli/publish.d.ts.map +1 -0
  50. package/dist/cli/publish.js +76 -0
  51. package/dist/cli/publish.js.map +1 -0
  52. package/dist/index.d.ts +3 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +6 -0
  55. package/dist/index.js.map +1 -0
  56. package/migrations/0001_init.sql +19 -0
  57. package/package.json +89 -1
  58. package/src/Manifest.ts +76 -0
  59. package/src/Protocol.ts +163 -0
  60. package/src/Registry/Bindings.ts +134 -0
  61. package/src/Registry/GitHub.ts +365 -0
  62. package/src/Registry/Handler.ts +549 -0
  63. package/src/Registry/KVCache.ts +68 -0
  64. package/src/Registry/Sweep.ts +117 -0
  65. package/src/Registry/Tags.ts +117 -0
  66. package/src/Registry.ts +197 -0
  67. package/src/cli/bin.ts +101 -0
  68. package/src/cli/pack.ts +603 -0
  69. package/src/cli/publish.ts +129 -0
  70. package/src/index.ts +5 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,169 @@
1
+ import * as Config from "effect/Config";
2
+ import * as Effect from "effect/Effect";
3
+ import * as FileSystem from "effect/FileSystem";
4
+ import * as Path from "effect/Path";
5
+ import * as Schema from "effect/Schema";
6
+ declare const WorkspaceError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
7
+ readonly _tag: "WorkspaceError";
8
+ } & Readonly<A>;
9
+ export declare class WorkspaceError extends WorkspaceError_base<{
10
+ readonly message: string;
11
+ }> {
12
+ }
13
+ /**
14
+ * A `--group` flag, `NAME=GLOB` or `NAME[Collapsed]=GLOB`, e.g.
15
+ * `Alchemy=./packages/*` or `Distilled[Collapsed]=./submodules/distilled/packages/*`.
16
+ * `Collapsed` is the only attribute.
17
+ */
18
+ export declare const Group: Schema.decodeTo<Schema.Struct<{
19
+ readonly name: Schema.String;
20
+ readonly pattern: Schema.String;
21
+ /** Render the group collapsed in the install comment. */
22
+ readonly collapsed: Schema.Boolean;
23
+ }>, Schema.String, never, never>;
24
+ export type Group = typeof Group.Type;
25
+ /** The subset of `package.json` the CLI reads. Extra keys are preserved on the raw object. */
26
+ export declare const PackageJson: Schema.Struct<{
27
+ readonly name: Schema.optionalKey<Schema.String>;
28
+ readonly version: Schema.optionalKey<Schema.String>;
29
+ readonly private: Schema.optionalKey<Schema.Boolean>;
30
+ }>;
31
+ export declare const DEPENDENCY_SECTIONS: readonly ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
32
+ export declare const DependencySections: Schema.Struct<{
33
+ readonly dependencies: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
34
+ readonly devDependencies: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
35
+ readonly peerDependencies: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
36
+ readonly optionalDependencies: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
37
+ }>;
38
+ /**
39
+ * Order packages so every package comes after the packed packages it
40
+ * depends on, grouped into levels that can be packed concurrently. Fails on
41
+ * a cycle, since a tarball cannot link to a dependency that links back.
42
+ */
43
+ export declare const dependencyLevels: (dependencies: ReadonlyMap<string, ReadonlySet<string>>) => Effect.Effect<string[][], WorkspaceError, never>;
44
+ export interface WorkspacePackage {
45
+ readonly name: string;
46
+ readonly version: string;
47
+ /** Relative to the workspace root, POSIX separators. */
48
+ readonly dir: string;
49
+ readonly absDir: string;
50
+ readonly group: string;
51
+ }
52
+ /**
53
+ * Expand one level of `{a,b,c}` alternatives into plain patterns, so
54
+ * `./packages/{alchemy,pkg}` lists exactly those two directories.
55
+ */
56
+ export declare const expandBraces: (pattern: string) => string[];
57
+ /**
58
+ * Discover publishable packages under each group's pattern, in the order the
59
+ * groups and their directories were given, which is the order they are
60
+ * listed in. Private packages and directories without a named
61
+ * `package.json` are skipped. A package name appearing under two groups is
62
+ * an error.
63
+ */
64
+ export declare const discover: (cwd: string, groups: readonly {
65
+ readonly name: string;
66
+ readonly pattern: string;
67
+ readonly collapsed: boolean;
68
+ }[]) => Effect.Effect<WorkspacePackage[], import("effect/PlatformError").PlatformError | Schema.SchemaError | WorkspaceError, FileSystem.FileSystem | Path.Path>;
69
+ declare const GitError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
70
+ readonly _tag: "GitError";
71
+ } & Readonly<A>;
72
+ export declare class GitError extends GitError_base<{
73
+ readonly args: ReadonlyArray<string>;
74
+ readonly cwd: string;
75
+ readonly exitCode: number;
76
+ readonly stderr: string;
77
+ }> {
78
+ get message(): string;
79
+ }
80
+ /** Run `git` in `cwd` and return trimmed stdout. */
81
+ export declare const git: (cwd: string, args: readonly string[]) => Effect.Effect<string, GitError | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
82
+ /** Absolute path of the repository (or submodule) that owns `cwd`. */
83
+ export declare const toplevel: (cwd: string) => Effect.Effect<string, GitError | import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner>;
84
+ declare const PackError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
85
+ readonly _tag: "PackError";
86
+ } & Readonly<A>;
87
+ export declare class PackError extends PackError_base<{
88
+ readonly dir: string;
89
+ readonly message: string;
90
+ }> {
91
+ }
92
+ /**
93
+ * Rewrite every dependency on a package in `links` to that package's
94
+ * tarball URL. Returns the rewritten manifest text and the rewrites made.
95
+ */
96
+ export declare const rewriteDependencies: (manifestText: string, links: ReadonlyMap<string, string>) => Effect.Effect<{
97
+ text: string;
98
+ rewrites: {
99
+ section: string;
100
+ name: string;
101
+ url: string;
102
+ }[];
103
+ }, Schema.SchemaError, never>;
104
+ export interface PackedTarball {
105
+ readonly file: string;
106
+ readonly sha256: string;
107
+ readonly size: number;
108
+ readonly rewrites: ReadonlyArray<{
109
+ section: string;
110
+ name: string;
111
+ url: string;
112
+ }>;
113
+ }
114
+ /**
115
+ * Pack one package with pnpm, rewrite its dependencies on already-packed
116
+ * packages to their tarball URLs, and repack reproducibly into `outDir/file`.
117
+ */
118
+ export declare const packPackage: (options: {
119
+ readonly absDir: string;
120
+ /** Tarball URL of every already-packed dependency, by package name. */
121
+ readonly links: ReadonlyMap<string, string>;
122
+ readonly outDir: string;
123
+ readonly file: string;
124
+ }) => Effect.Effect<{
125
+ file: string;
126
+ sha256: string;
127
+ size: number;
128
+ rewrites: readonly {
129
+ section: string;
130
+ name: string;
131
+ url: string;
132
+ }[];
133
+ }, PackError | import("effect/PlatformError").PlatformError | Schema.SchemaError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem | Path.Path | import("effect/Scope").Scope>;
134
+ export interface PackOptions {
135
+ readonly cwd: string;
136
+ readonly groups: ReadonlyArray<Group>;
137
+ readonly registry: string;
138
+ readonly out: string;
139
+ }
140
+ /**
141
+ * Tarball file name for a package: `@` dropped and the scope separator
142
+ * replaced by `+`, a character package names cannot contain, so `@a/b-c`
143
+ * and `@a-b/c` get distinct files.
144
+ */
145
+ export declare const tarballFile: (name: string) => string;
146
+ /**
147
+ * Pack every discovered package into `out` with a manifest describing each
148
+ * tarball. Nothing here talks to the registry.
149
+ */
150
+ export declare const pack: (options: PackOptions) => Effect.Effect<{
151
+ readonly version: 1;
152
+ readonly groups: readonly {
153
+ readonly name: string;
154
+ readonly collapsed: boolean;
155
+ }[];
156
+ readonly registry: string;
157
+ readonly head: string;
158
+ readonly packages: readonly {
159
+ readonly name: string;
160
+ readonly version: string;
161
+ readonly dir: string;
162
+ readonly group: string;
163
+ readonly file: string;
164
+ readonly sha256: string;
165
+ readonly size: number;
166
+ }[];
167
+ } | undefined, Config.ConfigError | GitError | PackError | import("effect/PlatformError").PlatformError | Schema.SchemaError | WorkspaceError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | FileSystem.FileSystem | Path.Path>;
168
+ export {};
169
+ //# sourceMappingURL=pack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/cli/pack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,447 @@
1
+ import * as Config from "effect/Config";
2
+ import * as Console from "effect/Console";
3
+ import * as Data from "effect/Data";
4
+ import * as Effect from "effect/Effect";
5
+ import * as FileSystem from "effect/FileSystem";
6
+ import * as Option from "effect/Option";
7
+ import * as Path from "effect/Path";
8
+ import * as Schema from "effect/Schema";
9
+ import * as SchemaIssue from "effect/SchemaIssue";
10
+ import * as SchemaTransformation from "effect/SchemaTransformation";
11
+ import * as ChildProcess from "effect/unstable/process/ChildProcess";
12
+ import { exec } from "alchemy/Util/exec";
13
+ import { sha256 } from "alchemy/Util/sha256";
14
+ import { packTar, unpackTar } from "modern-tar";
15
+ import { gunzipSync, gzipSync } from "node:zlib";
16
+ import { GroupName, MANIFEST_FILE, ManifestJson, } from "../Manifest.js";
17
+ import { manifestArtifactName, tarballUrl } from "../Protocol.js";
18
+ export class WorkspaceError extends Data.TaggedError("WorkspaceError") {
19
+ }
20
+ const GROUP_SPEC = /^([^[=]+?)\s*(?:\[([^\]]*)\])?\s*=\s*(.+?)\s*$/;
21
+ /**
22
+ * A `--group` flag, `NAME=GLOB` or `NAME[Collapsed]=GLOB`, e.g.
23
+ * `Alchemy=./packages/*` or `Distilled[Collapsed]=./submodules/distilled/packages/*`.
24
+ * `Collapsed` is the only attribute.
25
+ */
26
+ export const Group = Schema.String.pipe(Schema.decodeTo(Schema.Struct({
27
+ name: GroupName,
28
+ pattern: Schema.String,
29
+ /** Render the group collapsed in the install comment. */
30
+ collapsed: Schema.Boolean,
31
+ }), SchemaTransformation.transformEffect({
32
+ decode: (spec, options) => {
33
+ const match = spec.match(GROUP_SPEC);
34
+ const attributes = (match?.[2] ?? "")
35
+ .split(",")
36
+ .map((attribute) => attribute.trim())
37
+ .filter((attribute) => attribute.length > 0);
38
+ return match &&
39
+ attributes.every((attribute) => attribute === "Collapsed")
40
+ ? Effect.succeed({
41
+ name: match[1],
42
+ pattern: match[3],
43
+ collapsed: attributes.includes("Collapsed"),
44
+ })
45
+ : Effect.fail(new SchemaIssue.InvalidValue({ expected: "NAME=GLOB or NAME[Collapsed]=GLOB" }, spec, options));
46
+ },
47
+ encode: (group) => Effect.succeed(`${group.name}${group.collapsed ? "[Collapsed]" : ""}=${group.pattern}`),
48
+ })));
49
+ /** The subset of `package.json` the CLI reads. Extra keys are preserved on the raw object. */
50
+ export const PackageJson = Schema.Struct({
51
+ name: Schema.optionalKey(Schema.String),
52
+ version: Schema.optionalKey(Schema.String),
53
+ private: Schema.optionalKey(Schema.Boolean),
54
+ });
55
+ export const DEPENDENCY_SECTIONS = [
56
+ "dependencies",
57
+ "devDependencies",
58
+ "peerDependencies",
59
+ "optionalDependencies",
60
+ ];
61
+ const DependencyMap = Schema.optionalKey(Schema.Record(Schema.String, Schema.String));
62
+ export const DependencySections = Schema.Struct({
63
+ dependencies: DependencyMap,
64
+ devDependencies: DependencyMap,
65
+ peerDependencies: DependencyMap,
66
+ optionalDependencies: DependencyMap,
67
+ });
68
+ /**
69
+ * Order packages so every package comes after the packed packages it
70
+ * depends on, grouped into levels that can be packed concurrently. Fails on
71
+ * a cycle, since a tarball cannot link to a dependency that links back.
72
+ */
73
+ export const dependencyLevels = Effect.fn("dependencyLevels")(function* (dependencies) {
74
+ const remaining = new Map([...dependencies].map(([name, deps]) => [
75
+ name,
76
+ new Set([...deps].filter((dep) => dependencies.has(dep))),
77
+ ]));
78
+ const levels = [];
79
+ while (remaining.size > 0) {
80
+ const ready = [...remaining]
81
+ .filter(([, deps]) => deps.size === 0)
82
+ .map(([name]) => name)
83
+ .sort();
84
+ if (ready.length === 0) {
85
+ return yield* new WorkspaceError({
86
+ message: `Dependency cycle among packed packages: ${[...remaining.keys()].sort().join(", ")}`,
87
+ });
88
+ }
89
+ for (const name of ready)
90
+ remaining.delete(name);
91
+ for (const deps of remaining.values()) {
92
+ for (const name of ready)
93
+ deps.delete(name);
94
+ }
95
+ levels.push(ready);
96
+ }
97
+ return levels;
98
+ });
99
+ /**
100
+ * Expand one level of `{a,b,c}` alternatives into plain patterns, so
101
+ * `./packages/{alchemy,pkg}` lists exactly those two directories.
102
+ */
103
+ export const expandBraces = (pattern) => {
104
+ const match = pattern.match(/^(.*?)\{([^{}]*)\}(.*)$/);
105
+ if (!match)
106
+ return [pattern];
107
+ return match[2]
108
+ .split(",")
109
+ .map((alternative) => alternative.trim())
110
+ .filter((alternative) => alternative.length > 0)
111
+ .flatMap((alternative) => expandBraces(`${match[1]}${alternative}${match[3]}`));
112
+ };
113
+ /**
114
+ * Expand a directory glob. `*` is supported as a whole path segment and
115
+ * `{a,b}` as a list of alternatives, which covers `./packages/*` and
116
+ * `./submodules/x/packages/{core,aws}`. Matches are directories only.
117
+ */
118
+ const expand = Effect.fn("expandGlob")(function* (cwd, glob) {
119
+ const results = [];
120
+ for (const pattern of expandBraces(glob)) {
121
+ results.push(...(yield* expandPattern(cwd, pattern)));
122
+ }
123
+ return [...new Set(results)];
124
+ });
125
+ const expandPattern = Effect.fn("expandPattern")(function* (cwd, pattern) {
126
+ const fs = yield* FileSystem.FileSystem;
127
+ const path = yield* Path.Path;
128
+ if (pattern.includes("**")) {
129
+ return yield* new WorkspaceError({
130
+ message: `Unsupported pattern ${JSON.stringify(pattern)}: only a single "*" segment is supported`,
131
+ });
132
+ }
133
+ const segments = pattern.split("/").filter((s) => s !== "" && s !== ".");
134
+ let current = [cwd];
135
+ for (const segment of segments) {
136
+ const next = [];
137
+ for (const base of current) {
138
+ if (segment === "*") {
139
+ const entries = yield* fs.readDirectory(base);
140
+ for (const entry of entries.sort()) {
141
+ const candidate = path.join(base, entry);
142
+ const stat = yield* fs.stat(candidate);
143
+ if (stat.type === "Directory")
144
+ next.push(candidate);
145
+ }
146
+ }
147
+ else if (segment.includes("*")) {
148
+ return yield* new WorkspaceError({
149
+ message: `Unsupported pattern ${JSON.stringify(pattern)}: "*" must be a whole path segment`,
150
+ });
151
+ }
152
+ else {
153
+ const candidate = path.join(base, segment);
154
+ if (yield* fs.exists(candidate))
155
+ next.push(candidate);
156
+ }
157
+ }
158
+ current = next;
159
+ }
160
+ return current;
161
+ });
162
+ /**
163
+ * Discover publishable packages under each group's pattern, in the order the
164
+ * groups and their directories were given, which is the order they are
165
+ * listed in. Private packages and directories without a named
166
+ * `package.json` are skipped. A package name appearing under two groups is
167
+ * an error.
168
+ */
169
+ export const discover = Effect.fn("discoverPackages")(function* (cwd, groups) {
170
+ const fs = yield* FileSystem.FileSystem;
171
+ const path = yield* Path.Path;
172
+ const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(PackageJson));
173
+ const found = new Map();
174
+ for (const group of groups) {
175
+ for (const absDir of yield* expand(cwd, group.pattern)) {
176
+ const manifestPath = path.join(absDir, "package.json");
177
+ if (!(yield* fs.exists(manifestPath)))
178
+ continue;
179
+ const manifest = yield* decode(yield* fs.readFileString(manifestPath));
180
+ if (manifest.private || manifest.name === undefined)
181
+ continue;
182
+ const existing = found.get(manifest.name);
183
+ if (existing !== undefined) {
184
+ return yield* new WorkspaceError({
185
+ message: `Package ${manifest.name} found in both ${existing.dir} and ${path.relative(cwd, absDir)}`,
186
+ });
187
+ }
188
+ found.set(manifest.name, {
189
+ name: manifest.name,
190
+ version: manifest.version ?? "0.0.0",
191
+ dir: path.relative(cwd, absDir).split(path.sep).join("/"),
192
+ absDir,
193
+ group: group.name,
194
+ });
195
+ }
196
+ }
197
+ return [...found.values()];
198
+ });
199
+ export class GitError extends Data.TaggedError("GitError") {
200
+ get message() {
201
+ return `git ${this.args.join(" ")} in ${this.cwd} exited with ${this.exitCode}: ${this.stderr.trim()}`;
202
+ }
203
+ }
204
+ /** Run `git` in `cwd` and return trimmed stdout. */
205
+ export const git = Effect.fn("git")(function* (cwd, args) {
206
+ const { exitCode, stdout, stderr } = yield* exec(ChildProcess.make("git", [...args], { cwd, shell: false })).pipe(Effect.scoped);
207
+ if (exitCode !== 0) {
208
+ return yield* new GitError({ args, cwd, exitCode, stderr });
209
+ }
210
+ return stdout.trim();
211
+ });
212
+ /** Absolute path of the repository (or submodule) that owns `cwd`. */
213
+ export const toplevel = (cwd) => git(cwd, ["rev-parse", "--show-toplevel"]);
214
+ /** Full HEAD SHA of the repository that owns `cwd`. */
215
+ const gitHead = (cwd) => git(cwd, ["rev-parse", "HEAD"]);
216
+ export class PackError extends Data.TaggedError("PackError") {
217
+ }
218
+ const PnpmPackOutput = Schema.fromJsonString(Schema.Struct({ filename: Schema.String }));
219
+ /**
220
+ * Rewrite every dependency on a package in `links` to that package's
221
+ * tarball URL. Returns the rewritten manifest text and the rewrites made.
222
+ */
223
+ export const rewriteDependencies = (manifestText, links) => Effect.gen(function* () {
224
+ const manifest = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.StructWithRest(DependencySections, [
225
+ Schema.Record(Schema.String, Schema.Unknown),
226
+ ])))(manifestText);
227
+ // Preserve source key order after validation: it contributes to the tarball hash.
228
+ const rewritten = JSON.parse(manifestText);
229
+ const rewrites = [];
230
+ for (const section of DEPENDENCY_SECTIONS) {
231
+ const deps = manifest[section];
232
+ if (deps === undefined)
233
+ continue;
234
+ const next = { ...deps };
235
+ for (const name of Object.keys(deps)) {
236
+ const url = links.get(name);
237
+ if (url === undefined)
238
+ continue;
239
+ next[name] = url;
240
+ rewrites.push({ section, name, url });
241
+ }
242
+ rewritten[section] = next;
243
+ }
244
+ return { text: `${JSON.stringify(rewritten, null, 2)}\n`, rewrites };
245
+ });
246
+ const EPOCH = new Date(0);
247
+ /**
248
+ * Normalize tar headers so identical inputs produce identical bytes:
249
+ * fixed mtime, no ownership, entries sorted by path.
250
+ */
251
+ const normalize = (header, size) => ({
252
+ name: header.name,
253
+ size,
254
+ mode: header.mode,
255
+ type: header.type ?? "file",
256
+ mtime: EPOCH,
257
+ uid: 0,
258
+ gid: 0,
259
+ uname: "",
260
+ gname: "",
261
+ ...(header.linkname !== undefined ? { linkname: header.linkname } : {}),
262
+ });
263
+ /**
264
+ * Pack one package with pnpm, rewrite its dependencies on already-packed
265
+ * packages to their tarball URLs, and repack reproducibly into `outDir/file`.
266
+ */
267
+ export const packPackage = Effect.fn("packPackage")(function* (options) {
268
+ const fs = yield* FileSystem.FileSystem;
269
+ const path = yield* Path.Path;
270
+ const tmp = yield* fs.makeTempDirectoryScoped({ prefix: "pkg-pack-" });
271
+ const { exitCode, stdout, stderr } = yield* exec(ChildProcess.make("pnpm", ["pack", "--json", "--pack-destination", tmp], {
272
+ cwd: options.absDir,
273
+ shell: false,
274
+ }));
275
+ if (exitCode !== 0) {
276
+ return yield* new PackError({
277
+ dir: options.absDir,
278
+ message: `pnpm pack exited with ${exitCode}: ${stderr.trim() || stdout.trim()}`,
279
+ });
280
+ }
281
+ // pnpm may print progress lines before the JSON document.
282
+ const json = stdout.slice(stdout.indexOf("{"));
283
+ const { filename } = yield* Schema.decodeUnknownEffect(PnpmPackOutput)(json);
284
+ const packed = yield* fs.readFile(path.join(tmp, path.basename(filename)));
285
+ const inflated = yield* Effect.sync(() => gunzipSync(packed));
286
+ const entries = yield* Effect.promise(() => unpackTar(inflated));
287
+ let rewrites = [];
288
+ const normalized = [];
289
+ for (const entry of entries.sort((a, b) => a.header.name.localeCompare(b.header.name))) {
290
+ let data = entry.data ?? new Uint8Array();
291
+ if (entry.header.name === "package/package.json") {
292
+ const text = yield* Effect.sync(() => new TextDecoder().decode(data));
293
+ const result = yield* rewriteDependencies(text, options.links).pipe(Effect.mapError((e) => new PackError({ dir: options.absDir, message: String(e) })));
294
+ rewrites = result.rewrites;
295
+ data = yield* Effect.sync(() => new TextEncoder().encode(result.text));
296
+ }
297
+ normalized.push({ header: normalize(entry.header, data.byteLength), data });
298
+ }
299
+ const tar = yield* Effect.promise(() => packTar(normalized));
300
+ const bytes = yield* Effect.sync(() => gzipSync(tar, { level: 9 }));
301
+ yield* fs.writeFile(path.join(options.outDir, options.file), bytes);
302
+ return {
303
+ file: options.file,
304
+ sha256: yield* sha256(bytes),
305
+ size: bytes.byteLength,
306
+ rewrites,
307
+ };
308
+ });
309
+ const PullRequestEvent = Schema.fromJsonString(Schema.Struct({
310
+ pull_request: Schema.optionalKey(Schema.Struct({ head: Schema.Struct({ sha: Schema.String }) })),
311
+ }));
312
+ /**
313
+ * The pull request head commit when running under a GitHub Actions
314
+ * `pull_request` event, read from the event payload. `undefined` elsewhere.
315
+ * On that event the default checkout is a synthetic merge commit, which the
316
+ * registry would reject because it does not match the run's head.
317
+ */
318
+ const pullRequestHead = Effect.gen(function* () {
319
+ const event = yield* Config.option(Config.String("GITHUB_EVENT_NAME"));
320
+ const eventPath = yield* Config.option(Config.String("GITHUB_EVENT_PATH"));
321
+ if (Option.getOrUndefined(event) !== "pull_request" ||
322
+ Option.isNone(eventPath)) {
323
+ return undefined;
324
+ }
325
+ const fs = yield* FileSystem.FileSystem;
326
+ const payload = yield* fs
327
+ .readFileString(eventPath.value)
328
+ .pipe(Effect.flatMap(Schema.decodeUnknownEffect(PullRequestEvent)));
329
+ return payload.pull_request?.head.sha;
330
+ });
331
+ /**
332
+ * Tarball file name for a package: `@` dropped and the scope separator
333
+ * replaced by `+`, a character package names cannot contain, so `@a/b-c`
334
+ * and `@a-b/c` get distinct files.
335
+ */
336
+ export const tarballFile = (name) => `${name.replace(/^@/, "").replace("/", "+")}.tgz`;
337
+ /**
338
+ * Pack every discovered package into `out` with a manifest describing each
339
+ * tarball. Nothing here talks to the registry.
340
+ */
341
+ export const pack = Effect.fn("pack")(function* (options) {
342
+ const fs = yield* FileSystem.FileSystem;
343
+ const path = yield* Path.Path;
344
+ const root = yield* toplevel(options.cwd);
345
+ const head = yield* gitHead(root);
346
+ const prHead = yield* pullRequestHead;
347
+ if (prHead !== undefined && prHead !== head) {
348
+ return yield* new WorkspaceError({
349
+ message: `HEAD is ${head} but the pull request head is ${prHead}. ` +
350
+ "Check out github.event.pull_request.head.sha before packing so tarballs are addressed by a commit that exists on the pull request.",
351
+ });
352
+ }
353
+ const packages = yield* discover(options.cwd, options.groups);
354
+ if (packages.length === 0) {
355
+ yield* Console.log("No publishable packages matched.");
356
+ return undefined;
357
+ }
358
+ // Dependencies between packed packages are rewritten to the dependency's
359
+ // immutable tarball URL, so a package is packed only after everything it
360
+ // depends on has a hash.
361
+ const byName = new Map(packages.map((pkg) => [pkg.name, pkg]));
362
+ const dependencies = new Map();
363
+ for (const pkg of packages) {
364
+ const manifest = yield* fs
365
+ .readFileString(path.join(pkg.absDir, "package.json"))
366
+ .pipe(Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(DependencySections))));
367
+ dependencies.set(pkg.name, new Set(DEPENDENCY_SECTIONS.flatMap((section) => Object.keys(manifest[section] ?? {})).filter((name) => name !== pkg.name && byName.has(name))));
368
+ }
369
+ const levels = yield* dependencyLevels(dependencies);
370
+ // The output directory is replaced wholesale, so it has to be a proper
371
+ // subdirectory of the workspace: `--out .` would otherwise delete it.
372
+ const outDir = path.resolve(options.cwd, options.out);
373
+ const relative = path.relative(options.cwd, outDir);
374
+ if (relative === "" ||
375
+ relative.startsWith("..") ||
376
+ path.isAbsolute(relative)) {
377
+ return yield* new WorkspaceError({
378
+ message: `--out must be a subdirectory of ${options.cwd}, got ${outDir}`,
379
+ });
380
+ }
381
+ yield* fs.remove(outDir, { recursive: true, force: true });
382
+ yield* fs.makeDirectory(outDir, { recursive: true });
383
+ const links = new Map();
384
+ const packedByName = new Map();
385
+ for (const level of levels) {
386
+ const packedLevel = yield* Effect.forEach(level, Effect.fn(function* (name) {
387
+ const pkg = byName.get(name);
388
+ const packed = yield* packPackage({
389
+ absDir: pkg.absDir,
390
+ links,
391
+ outDir,
392
+ file: tarballFile(pkg.name),
393
+ }).pipe(Effect.scoped);
394
+ const lines = [
395
+ `${pkg.name}@${pkg.version} ${packed.sha256.slice(0, 12)} ${packed.size} bytes`,
396
+ ...packed.rewrites.map((r) => ` ${r.section}.${r.name} -> ${r.url}`),
397
+ ];
398
+ yield* Console.log(lines.join("\n"));
399
+ return {
400
+ name: pkg.name,
401
+ version: pkg.version,
402
+ dir: pkg.dir,
403
+ group: pkg.group,
404
+ file: packed.file,
405
+ sha256: packed.sha256,
406
+ size: packed.size,
407
+ };
408
+ }), { concurrency: 4 });
409
+ for (const entry of packedLevel) {
410
+ links.set(entry.name, tarballUrl(options.registry, entry.name, entry.sha256));
411
+ packedByName.set(entry.name, entry);
412
+ }
413
+ }
414
+ // Packing ran in dependency order; the manifest keeps the listed order.
415
+ const entries = packages.map((pkg) => packedByName.get(pkg.name));
416
+ // One entry per distinct group name, in the order the groups were given.
417
+ const groups = [
418
+ ...new Map(options.groups.map((group) => [
419
+ group.name,
420
+ { name: group.name, collapsed: group.collapsed },
421
+ ])).values(),
422
+ ];
423
+ const manifest = {
424
+ version: 1,
425
+ groups,
426
+ registry: options.registry.replace(/\/+$/, ""),
427
+ head,
428
+ packages: entries,
429
+ };
430
+ const manifestText = `${yield* Schema.encodeEffect(ManifestJson)(manifest)}\n`;
431
+ yield* fs.writeFileString(path.join(outDir, MANIFEST_FILE), manifestText);
432
+ yield* Console.log(`Packed ${entries.length} package(s) into ${path.relative(options.cwd, outDir) || "."}`);
433
+ // The workflow uploads the manifest as an artifact under this name; that
434
+ // upload is what proves to the registry that this run vouched for it.
435
+ // Only a JavaScript action receives the runtime token needed to upload,
436
+ // so the CLI cannot do it itself.
437
+ const artifact = manifestArtifactName(yield* sha256(manifestText));
438
+ const stepOutput = yield* Config.option(Config.String("GITHUB_OUTPUT"));
439
+ if (Option.isSome(stepOutput)) {
440
+ yield* fs.writeFileString(stepOutput.value, `artifact-name=${artifact}\n`, {
441
+ flag: "a",
442
+ });
443
+ }
444
+ yield* Console.log(`Manifest artifact name: ${artifact}`);
445
+ return manifest;
446
+ });
447
+ //# sourceMappingURL=pack.js.map