@decohere/create 0.0.1-dev.45 → 0.0.1-dev.46
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/pack-builder-tgz.mjs +163 -0
- package/package.json +2 -2
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pack `@decohere/create` for the builder image with production deps bundled
|
|
4
|
+
* from dist/release (local `file:` for `@decohere/*`) so `npm install -g --offline`
|
|
5
|
+
* does not hit the registry.
|
|
6
|
+
*/
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { readdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {{ name: string, dir: string }} WorkspacePackage
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} rootDir
|
|
18
|
+
* @returns {WorkspacePackage[]}
|
|
19
|
+
*/
|
|
20
|
+
export function collectWorkspacePackages(rootDir) {
|
|
21
|
+
/** @type {WorkspacePackage[]} */
|
|
22
|
+
const found = [];
|
|
23
|
+
const walk = (dir) => {
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
27
|
+
} catch {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
32
|
+
const path = join(dir, entry.name);
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
walk(path);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (entry.name !== "package.json") continue;
|
|
38
|
+
const pkg = JSON.parse(readFileSync(path, "utf8"));
|
|
39
|
+
if (typeof pkg.name === "string" && pkg.name.startsWith("@decohere/")) {
|
|
40
|
+
found.push({ name: pkg.name, dir });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
walk(rootDir);
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} fromDir
|
|
50
|
+
* @param {WorkspacePackage[]} packages
|
|
51
|
+
* @returns {Record<string, string>}
|
|
52
|
+
*/
|
|
53
|
+
export function decohereFileOverrides(fromDir, packages) {
|
|
54
|
+
/** @type {Record<string, string>} */
|
|
55
|
+
const overrides = {};
|
|
56
|
+
const from = resolve(fromDir);
|
|
57
|
+
for (const pkg of packages) {
|
|
58
|
+
if (resolve(pkg.dir) === from) continue;
|
|
59
|
+
let rel = relative(fromDir, pkg.dir) || ".";
|
|
60
|
+
rel = rel.replaceAll("\\", "/");
|
|
61
|
+
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
62
|
+
overrides[pkg.name] = `file:${rel}`;
|
|
63
|
+
}
|
|
64
|
+
return overrides;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Record<string, unknown>} pkg
|
|
69
|
+
* @returns {string[]}
|
|
70
|
+
*/
|
|
71
|
+
export function productionDepNames(pkg) {
|
|
72
|
+
const deps = pkg.dependencies;
|
|
73
|
+
if (deps == null || typeof deps !== "object") return [];
|
|
74
|
+
return Object.keys(deps);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {Record<string, unknown>} pkg
|
|
79
|
+
* @param {Record<string, string>} overrides
|
|
80
|
+
*/
|
|
81
|
+
export function withInstallOverrides(pkg, overrides) {
|
|
82
|
+
const existing = pkg.overrides;
|
|
83
|
+
const previous =
|
|
84
|
+
existing != null && typeof existing === "object" && !Array.isArray(existing)
|
|
85
|
+
? /** @type {Record<string, unknown>} */ (existing)
|
|
86
|
+
: {};
|
|
87
|
+
return { ...pkg, overrides: { ...previous, ...overrides } };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {Record<string, unknown>} pkg
|
|
92
|
+
*/
|
|
93
|
+
export function withBundleDependencies(pkg) {
|
|
94
|
+
const { overrides: _overrides, ...rest } = pkg;
|
|
95
|
+
return { ...rest, bundleDependencies: productionDepNames(pkg) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function writeJson(path, value) {
|
|
99
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function runNpm(cwd, args) {
|
|
103
|
+
const result = spawnSync("npm", args, { cwd, encoding: "utf8" });
|
|
104
|
+
if (result.status !== 0) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`npm ${args.join(" ")} failed (exit ${result.status}):\n${result.stderr}${result.stdout}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return result.stdout.trim();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function packBuilderTgz(options) {
|
|
113
|
+
const outDir = resolve(options.outDir);
|
|
114
|
+
const workspaceOut = resolve(options.workspaceOut);
|
|
115
|
+
const dest = resolve(options.dest);
|
|
116
|
+
const packageJsonPath = join(outDir, "package.json");
|
|
117
|
+
const original = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
118
|
+
const overrides = decohereFileOverrides(outDir, collectWorkspacePackages(workspaceOut));
|
|
119
|
+
writeJson(packageJsonPath, withInstallOverrides(original, overrides));
|
|
120
|
+
runNpm(outDir, ["install", "--omit=dev", "--ignore-scripts"]);
|
|
121
|
+
writeJson(packageJsonPath, withBundleDependencies(original));
|
|
122
|
+
const packed = runNpm(outDir, ["pack", "--pack-destination", dirname(dest)]);
|
|
123
|
+
const tgzName = packed.split(/\r?\n/).at(-1)?.replace(/^.*\//, "");
|
|
124
|
+
if (tgzName == null || tgzName === "") {
|
|
125
|
+
throw new Error(`npm pack did not print a tarball name:\n${packed}`);
|
|
126
|
+
}
|
|
127
|
+
renameSync(join(dirname(dest), tgzName), dest);
|
|
128
|
+
return dest;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function parseArgs(argv) {
|
|
132
|
+
/** @type {Record<string, string>} */
|
|
133
|
+
const parsed = {};
|
|
134
|
+
for (let i = 0; i < argv.length; i++) {
|
|
135
|
+
const arg = argv[i];
|
|
136
|
+
if (arg == null || !arg.startsWith("--")) continue;
|
|
137
|
+
const key = arg.slice(2);
|
|
138
|
+
const value = argv[i + 1];
|
|
139
|
+
if (value == null || value.startsWith("--")) {
|
|
140
|
+
throw new Error(`Missing value for --${key}`);
|
|
141
|
+
}
|
|
142
|
+
parsed[key] = value;
|
|
143
|
+
i++;
|
|
144
|
+
}
|
|
145
|
+
return parsed;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function main() {
|
|
149
|
+
const args = parseArgs(process.argv.slice(2));
|
|
150
|
+
const outDir = args["out-dir"];
|
|
151
|
+
const workspaceOut = args["workspace-out"];
|
|
152
|
+
const dest = args.dest;
|
|
153
|
+
if (outDir == null || workspaceOut == null || dest == null) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
"Usage: pack-builder-tgz.mjs --out-dir <dir> --workspace-out <dir> --dest <create.tgz>",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
packBuilderTgz({ outDir, workspaceOut, dest });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (process.argv[1] != null && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
162
|
+
main();
|
|
163
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decohere/create",
|
|
3
|
-
"version": "0.0.1-dev.
|
|
3
|
+
"version": "0.0.1-dev.46",
|
|
4
4
|
"description": "Scaffold a new Decohere project — build with Forge, serve with Flux",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"decohere",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@decohere/nexus": "0.0.1-dev.
|
|
24
|
+
"@decohere/nexus": "0.0.1-dev.46",
|
|
25
25
|
"commander": "^13.1.0",
|
|
26
26
|
"openapi-to-postmanv2": "^5.0.0"
|
|
27
27
|
},
|