hatchkit 0.1.35 → 0.1.37
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/dist/adopt.d.ts.map +1 -1
- package/dist/adopt.js +167 -1
- package/dist/adopt.js.map +1 -1
- package/dist/assets/env.d.ts +40 -0
- package/dist/assets/env.d.ts.map +1 -0
- package/dist/assets/env.js +150 -0
- package/dist/assets/env.js.map +1 -0
- package/dist/assets/index.d.ts +2 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +328 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/assets/mirror.d.ts +59 -0
- package/dist/assets/mirror.d.ts.map +1 -0
- package/dist/assets/mirror.js +251 -0
- package/dist/assets/mirror.js.map +1 -0
- package/dist/completion.d.ts.map +1 -1
- package/dist/completion.js +16 -0
- package/dist/completion.js.map +1 -1
- package/dist/config.d.ts +18 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +157 -50
- package/dist/config.js.map +1 -1
- package/dist/deploy/coolify-app.d.ts +6 -0
- package/dist/deploy/coolify-app.d.ts.map +1 -1
- package/dist/deploy/coolify-app.js +58 -15
- package/dist/deploy/coolify-app.js.map +1 -1
- package/dist/deploy/rename-domain.d.ts.map +1 -1
- package/dist/deploy/rename-domain.js +4 -2
- package/dist/deploy/rename-domain.js.map +1 -1
- package/dist/deploy/rollback.d.ts +11 -0
- package/dist/deploy/rollback.d.ts.map +1 -1
- package/dist/deploy/rollback.js +46 -9
- package/dist/deploy/rollback.js.map +1 -1
- package/dist/deploy/sync.d.ts +98 -0
- package/dist/deploy/sync.d.ts.map +1 -0
- package/dist/deploy/sync.js +354 -0
- package/dist/deploy/sync.js.map +1 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +29 -11
- package/dist/doctor.js.map +1 -1
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +5 -0
- package/dist/explain.js.map +1 -1
- package/dist/index.js +184 -30
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +7 -5
- package/dist/prompts.js.map +1 -1
- package/dist/provision/s3-buckets.d.ts +12 -5
- package/dist/provision/s3-buckets.d.ts.map +1 -1
- package/dist/provision/s3-buckets.js +14 -7
- package/dist/provision/s3-buckets.js.map +1 -1
- package/dist/provision/stripe.d.ts +85 -16
- package/dist/provision/stripe.d.ts.map +1 -1
- package/dist/provision/stripe.js +334 -28
- package/dist/provision/stripe.js.map +1 -1
- package/dist/provision/write-env.d.ts +7 -0
- package/dist/provision/write-env.d.ts.map +1 -1
- package/dist/provision/write-env.js +18 -0
- package/dist/provision/write-env.js.map +1 -1
- package/dist/scaffold/app.d.ts.map +1 -1
- package/dist/scaffold/app.js +7 -1
- package/dist/scaffold/app.js.map +1 -1
- package/dist/scaffold/infra.js +2 -2
- package/dist/scaffold/infra.js.map +1 -1
- package/dist/scaffold/manifest.d.ts +5 -0
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/starter-files.d.ts +22 -0
- package/dist/scaffold/starter-files.d.ts.map +1 -1
- package/dist/scaffold/starter-files.js +44 -0
- package/dist/scaffold/starter-files.js.map +1 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +11 -1
- package/dist/status.js.map +1 -1
- package/dist/templates/build-pipeline/docker-compose.yml.hbs +17 -0
- package/dist/utils/cancel-handler.d.ts +17 -0
- package/dist/utils/cancel-handler.d.ts.map +1 -0
- package/dist/utils/cancel-handler.js +97 -0
- package/dist/utils/cancel-handler.js.map +1 -0
- package/dist/utils/coolify-api.d.ts +60 -2
- package/dist/utils/coolify-api.d.ts.map +1 -1
- package/dist/utils/coolify-api.js +85 -2
- package/dist/utils/coolify-api.js.map +1 -1
- package/dist/utils/secrets.d.ts +29 -0
- package/dist/utils/secrets.d.ts.map +1 -1
- package/dist/utils/secrets.js +29 -0
- package/dist/utils/secrets.js.map +1 -1
- package/dist/utils/validate.d.ts +6 -0
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +17 -0
- package/dist/utils/validate.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Resolve the S3 connection a scaffolded project actually uses, in
|
|
3
|
+
* either `dev` or `prod` mode. The bucket the *runtime* talks to is
|
|
4
|
+
* the source of truth — we read the same .env files the runtime
|
|
5
|
+
* reads, not the global hatchkit config or keychain.
|
|
6
|
+
*
|
|
7
|
+
* Naming convention quirks (see provision/s3-buckets.ts):
|
|
8
|
+
*
|
|
9
|
+
* · For S3/AWS-style projects, the assets bucket name lives in the
|
|
10
|
+
* env (`S3_BUCKET_NAME` or `S3_BUCKET_NAME` again). The `_*_*`
|
|
11
|
+
* credential keys are `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`
|
|
12
|
+
* (AWS-prefixed) or `S3_ACCESS_KEY_ID` / `S3_SECRET_ACCESS_KEY`
|
|
13
|
+
* (generic).
|
|
14
|
+
* · For R2 the assets bucket name is NOT in env (the runtime never
|
|
15
|
+
* calls it directly — it's URL-driven). The bucket name lives in
|
|
16
|
+
* `.hatchkit.json` under `s3Buckets.assets.name`. R2 uses the
|
|
17
|
+
* `R2_*` prefix for its credentials.
|
|
18
|
+
*
|
|
19
|
+
* We normalise both shapes here so callers don't have to care.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { parse as parseDotenv } from "@dotenvx/dotenvx";
|
|
24
|
+
import { readManifest } from "../scaffold/manifest.js";
|
|
25
|
+
/** Load + decrypt the env vars that the runtime will see in `mode`. */
|
|
26
|
+
export function loadProjectEnv(opts) {
|
|
27
|
+
const serverDir = opts.serverDir ?? detectServerDir(opts.projectDir);
|
|
28
|
+
const filename = opts.mode === "prod" ? ".env.production" : ".env.development";
|
|
29
|
+
const envPath = join(serverDir, filename);
|
|
30
|
+
if (!existsSync(envPath)) {
|
|
31
|
+
throw new Error(`Expected ${envPath} (mode=${opts.mode}). Is this a hatchkit project? ` +
|
|
32
|
+
`Run from the project root, or pass --dir.`);
|
|
33
|
+
}
|
|
34
|
+
const src = readFileSync(envPath, "utf-8");
|
|
35
|
+
let privateKey;
|
|
36
|
+
if (opts.mode === "prod") {
|
|
37
|
+
privateKey = process.env.DOTENV_PRIVATE_KEY_PRODUCTION ?? readPrivateKey(opts.projectDir);
|
|
38
|
+
if (!privateKey) {
|
|
39
|
+
throw new Error(`Can't decrypt ${envPath}. No DOTENV_PRIVATE_KEY_PRODUCTION in env, ` +
|
|
40
|
+
`and no .env.keys at ${join(opts.projectDir, ".env.keys")} or ${join(serverDir, ".env.keys")}. ` +
|
|
41
|
+
`Run \`hatchkit keys show <project>\` and export the value, or restore .env.keys.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const parsed = parseDotenv(src, { privateKey, processEnv: {} });
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
/** Resolve the unified S3 config used by mirror operations. */
|
|
48
|
+
export function loadS3Config(opts) {
|
|
49
|
+
const env = loadProjectEnv(opts);
|
|
50
|
+
const serverDir = opts.serverDir ?? detectServerDir(opts.projectDir);
|
|
51
|
+
const manifest = readManifest(opts.projectDir);
|
|
52
|
+
const prefix = detectPrefix(env);
|
|
53
|
+
const accessKeyId = env[`${prefix}_ACCESS_KEY_ID`] ?? env.AWS_ACCESS_KEY_ID ?? env.S3_ACCESS_KEY_ID ?? "";
|
|
54
|
+
const secretAccessKey = env[`${prefix}_SECRET_ACCESS_KEY`] ??
|
|
55
|
+
env.AWS_SECRET_ACCESS_KEY ??
|
|
56
|
+
env.S3_SECRET_ACCESS_KEY ??
|
|
57
|
+
"";
|
|
58
|
+
const endpoint = env[`${prefix}_ENDPOINT`] ?? env.S3_ENDPOINT ?? defaultEndpointFor(prefix, env);
|
|
59
|
+
const region = env[`${prefix}_REGION`] ??
|
|
60
|
+
env.AWS_REGION ??
|
|
61
|
+
env.S3_REGION ??
|
|
62
|
+
(prefix === "R2" ? "auto" : "us-east-1");
|
|
63
|
+
const forcePathStyle = parseBool(env.S3_FORCE_PATH_STYLE) ?? prefix !== "AWS";
|
|
64
|
+
// Assets bucket — for R2, not in env, so fall back to the manifest.
|
|
65
|
+
// For S3/AWS the bucket env (`S3_BUCKET_NAME`) holds the assets name
|
|
66
|
+
// unless a state bucket was provisioned (in which case it holds the
|
|
67
|
+
// state name — see provision/s3-buckets.ts:459-465). Reconcile by
|
|
68
|
+
// preferring the manifest when it's present.
|
|
69
|
+
const assetsFromManifest = manifest?.s3Buckets?.assets;
|
|
70
|
+
const stateFromManifest = manifest?.s3Buckets?.state;
|
|
71
|
+
const bucketEnv = env[`${prefix}_BUCKET_NAME`] ?? env.S3_BUCKET_NAME ?? env.R2_STATE_BUCKET;
|
|
72
|
+
const assetsName = assetsFromManifest?.name ?? bucketEnv;
|
|
73
|
+
if (!assetsName) {
|
|
74
|
+
throw new Error(`Can't resolve the assets bucket name for mode=${opts.mode}. ` +
|
|
75
|
+
`No s3Buckets.assets in .hatchkit.json and no S3_BUCKET_NAME / R2_BUCKET_NAME in env. ` +
|
|
76
|
+
`If this is a fresh project, run \`hatchkit provision s3\` first.`);
|
|
77
|
+
}
|
|
78
|
+
const assetsPublicUrl = assetsFromManifest?.publicUrl ?? env.NEXT_PUBLIC_ASSETS_BASE_URL ?? env.S3_PUBLIC_URL ?? null;
|
|
79
|
+
const stateName = stateFromManifest?.name ?? env[`${prefix}_STATE_BUCKET`];
|
|
80
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
81
|
+
throw new Error(`Missing S3 credentials in ${join(serverDir, opts.mode === "prod" ? ".env.production" : ".env.development")}. ` +
|
|
82
|
+
`Looked for ${prefix}_ACCESS_KEY_ID / AWS_ACCESS_KEY_ID and the matching secret.`);
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
mode: opts.mode,
|
|
86
|
+
endpoint,
|
|
87
|
+
region,
|
|
88
|
+
accessKeyId,
|
|
89
|
+
secretAccessKey,
|
|
90
|
+
forcePathStyle,
|
|
91
|
+
buckets: {
|
|
92
|
+
assets: { name: assetsName, publicUrl: assetsPublicUrl },
|
|
93
|
+
...(stateName ? { state: { name: stateName } } : {}),
|
|
94
|
+
},
|
|
95
|
+
source: opts.mode === "prod" ? `${serverDir}/.env.production` : `${serverDir}/.env.development`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Detect the env-name prefix the project uses. Order matters — R2
|
|
99
|
+
* wins over AWS wins over S3 because the more specific prefixes
|
|
100
|
+
* signal an explicit choice while S3 is the generic fallback. */
|
|
101
|
+
function detectPrefix(env) {
|
|
102
|
+
if (env.R2_ENDPOINT || env.R2_ACCESS_KEY_ID)
|
|
103
|
+
return "R2";
|
|
104
|
+
if (env.AWS_ACCESS_KEY_ID && (env.S3_BUCKET_NAME || env.S3_ENDPOINT))
|
|
105
|
+
return "AWS";
|
|
106
|
+
return "S3";
|
|
107
|
+
}
|
|
108
|
+
function defaultEndpointFor(prefix, env) {
|
|
109
|
+
if (prefix === "AWS") {
|
|
110
|
+
const region = env.AWS_REGION ?? "us-east-1";
|
|
111
|
+
return `https://s3.${region}.amazonaws.com`;
|
|
112
|
+
}
|
|
113
|
+
// R2 / generic S3 require an explicit endpoint — surfacing the
|
|
114
|
+
// missing var here is more useful than a misleading default.
|
|
115
|
+
throw new Error(`No ${prefix}_ENDPOINT or S3_ENDPOINT set. For R2 set R2_ENDPOINT to https://<account-id>.r2.cloudflarestorage.com.`);
|
|
116
|
+
}
|
|
117
|
+
function parseBool(v) {
|
|
118
|
+
if (v === undefined)
|
|
119
|
+
return undefined;
|
|
120
|
+
return v === "true" || v === "1";
|
|
121
|
+
}
|
|
122
|
+
function detectServerDir(projectDir) {
|
|
123
|
+
// Conventions, in order: pnpm/npm workspace at packages/server, or
|
|
124
|
+
// a flat single-package project where the env file sits at root.
|
|
125
|
+
const candidate = join(projectDir, "packages", "server");
|
|
126
|
+
if (existsSync(join(candidate, ".env.example")) ||
|
|
127
|
+
existsSync(join(candidate, ".env.development"))) {
|
|
128
|
+
return candidate;
|
|
129
|
+
}
|
|
130
|
+
return projectDir;
|
|
131
|
+
}
|
|
132
|
+
/** Find the dotenvx private key for `production`. Searches the
|
|
133
|
+
* project root and packages/server for `.env.keys` (where dotenvx
|
|
134
|
+
* writes it locally). Caller falls back to the OS keychain. */
|
|
135
|
+
function readPrivateKey(projectDir) {
|
|
136
|
+
const candidates = [
|
|
137
|
+
join(projectDir, ".env.keys"),
|
|
138
|
+
join(projectDir, "packages", "server", ".env.keys"),
|
|
139
|
+
];
|
|
140
|
+
for (const path of candidates) {
|
|
141
|
+
if (!existsSync(path))
|
|
142
|
+
continue;
|
|
143
|
+
const text = readFileSync(path, "utf-8");
|
|
144
|
+
const m = text.match(/^DOTENV_PRIVATE_KEY_PRODUCTION="?([0-9a-fA-F]+)"?/m);
|
|
145
|
+
if (m)
|
|
146
|
+
return m[1];
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/assets/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"AAsCA,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkClE"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `hatchkit assets <subcommand>` — move bytes between the local
|
|
3
|
+
* MinIO bucket and the production bucket (or any S3-compatible
|
|
4
|
+
* source, for adoption).
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* seed ./seed/assets/ → local MinIO
|
|
8
|
+
* push local MinIO → prod bucket
|
|
9
|
+
* pull prod bucket → local MinIO
|
|
10
|
+
* migrate external bucket → prod bucket (--from-endpoint=… --from-bucket=…)
|
|
11
|
+
* list dev|prod List objects in a bucket
|
|
12
|
+
*
|
|
13
|
+
* All transfer commands take `--bucket assets|state` (default assets),
|
|
14
|
+
* `--dir <path>` (default cwd), `--dry-run`, and `--json`.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
|
+
import { resolve } from "node:path";
|
|
18
|
+
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
|
|
19
|
+
import chalk from "chalk";
|
|
20
|
+
import ora from "ora";
|
|
21
|
+
import { loadS3Config } from "./env.js";
|
|
22
|
+
import { buildS3Client, ensureBucket, formatBytes, mirror, } from "./mirror.js";
|
|
23
|
+
export async function handleAssets(args) {
|
|
24
|
+
const sub = args[0];
|
|
25
|
+
if (!sub || sub === "--help" || sub === "-h") {
|
|
26
|
+
printHelp();
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
const flags = parseCommon(args.slice(1));
|
|
30
|
+
try {
|
|
31
|
+
switch (sub) {
|
|
32
|
+
case "seed":
|
|
33
|
+
return await handleSeed(args.slice(1), flags);
|
|
34
|
+
case "push":
|
|
35
|
+
return await handlePush(flags);
|
|
36
|
+
case "pull":
|
|
37
|
+
return await handlePull(flags);
|
|
38
|
+
case "migrate":
|
|
39
|
+
return await handleMigrate(args.slice(1), flags);
|
|
40
|
+
case "list":
|
|
41
|
+
return await handleList(args.slice(1), flags);
|
|
42
|
+
default:
|
|
43
|
+
console.error(chalk.red(`Unknown subcommand: assets ${sub}`));
|
|
44
|
+
printHelp();
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
const msg = err.message;
|
|
50
|
+
if (flags.json) {
|
|
51
|
+
console.log(JSON.stringify({ ok: false, error: msg }));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.error(chalk.red(`\n ✗ ${msg}\n`));
|
|
55
|
+
}
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// seed — populate the local MinIO bucket from ./seed/assets/
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
async function handleSeed(rawArgs, flags) {
|
|
63
|
+
const fromArg = takeFlag(rawArgs, "--from");
|
|
64
|
+
const fromDir = resolve(flags.projectDir, fromArg ?? "seed/assets");
|
|
65
|
+
if (!existsSync(fromDir)) {
|
|
66
|
+
throw new Error(`Seed directory ${fromDir} doesn't exist. Create it (mkdir -p seed/assets) and drop files in, or pass --from <path>.`);
|
|
67
|
+
}
|
|
68
|
+
const dev = loadS3Config({ projectDir: flags.projectDir, mode: "dev" });
|
|
69
|
+
const target = endpoint(dev, flags.bucket, "local");
|
|
70
|
+
await ensureBucket(target);
|
|
71
|
+
return runMirror({
|
|
72
|
+
label: `seed → ${target.label} bucket "${target.bucket}"`,
|
|
73
|
+
flags,
|
|
74
|
+
run: () => mirror({
|
|
75
|
+
source: { kind: "dir", dir: fromDir, label: "seed/assets" },
|
|
76
|
+
target,
|
|
77
|
+
dryRun: flags.dryRun,
|
|
78
|
+
onObject: makeProgress(flags.json),
|
|
79
|
+
}),
|
|
80
|
+
extra: { from: fromDir },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// push — local MinIO → prod
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
async function handlePush(flags) {
|
|
87
|
+
const dev = loadS3Config({ projectDir: flags.projectDir, mode: "dev" });
|
|
88
|
+
const prod = loadS3Config({ projectDir: flags.projectDir, mode: "prod" });
|
|
89
|
+
const source = endpoint(dev, flags.bucket, "local");
|
|
90
|
+
const target = endpoint(prod, flags.bucket, "prod");
|
|
91
|
+
if (!flags.dryRun)
|
|
92
|
+
await ensureBucket(target);
|
|
93
|
+
return runMirror({
|
|
94
|
+
label: `push local → prod bucket "${target.bucket}"`,
|
|
95
|
+
flags,
|
|
96
|
+
run: () => mirror({
|
|
97
|
+
source,
|
|
98
|
+
target,
|
|
99
|
+
dryRun: flags.dryRun,
|
|
100
|
+
onObject: makeProgress(flags.json),
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// pull — prod → local MinIO (be careful: realistic data may include PII)
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
async function handlePull(flags) {
|
|
108
|
+
const dev = loadS3Config({ projectDir: flags.projectDir, mode: "dev" });
|
|
109
|
+
const prod = loadS3Config({ projectDir: flags.projectDir, mode: "prod" });
|
|
110
|
+
const source = endpoint(prod, flags.bucket, "prod");
|
|
111
|
+
const target = endpoint(dev, flags.bucket, "local");
|
|
112
|
+
if (!flags.dryRun)
|
|
113
|
+
await ensureBucket(target);
|
|
114
|
+
return runMirror({
|
|
115
|
+
label: `pull prod → local bucket "${target.bucket}"`,
|
|
116
|
+
flags,
|
|
117
|
+
run: () => mirror({
|
|
118
|
+
source,
|
|
119
|
+
target,
|
|
120
|
+
dryRun: flags.dryRun,
|
|
121
|
+
onObject: makeProgress(flags.json),
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// migrate — external bucket → prod (the adoption escape hatch)
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
async function handleMigrate(rawArgs, flags) {
|
|
129
|
+
const fromEndpoint = takeFlag(rawArgs, "--from-endpoint");
|
|
130
|
+
const fromBucket = takeFlag(rawArgs, "--from-bucket");
|
|
131
|
+
const fromKey = takeFlag(rawArgs, "--from-key") ?? process.env.HATCHKIT_FROM_ACCESS_KEY_ID;
|
|
132
|
+
const fromSecret = takeFlag(rawArgs, "--from-secret") ?? process.env.HATCHKIT_FROM_SECRET_ACCESS_KEY;
|
|
133
|
+
const fromRegion = takeFlag(rawArgs, "--from-region") ?? "auto";
|
|
134
|
+
const fromPrefix = takeFlag(rawArgs, "--from-prefix");
|
|
135
|
+
const missing = [];
|
|
136
|
+
if (!fromBucket)
|
|
137
|
+
missing.push("--from-bucket");
|
|
138
|
+
if (!fromKey)
|
|
139
|
+
missing.push("--from-key (or env HATCHKIT_FROM_ACCESS_KEY_ID)");
|
|
140
|
+
if (!fromSecret)
|
|
141
|
+
missing.push("--from-secret (or env HATCHKIT_FROM_SECRET_ACCESS_KEY)");
|
|
142
|
+
if (missing.length > 0) {
|
|
143
|
+
throw new Error(`assets migrate is missing: ${missing.join(", ")}. ` +
|
|
144
|
+
`Run \`hatchkit help assets\` for the full flag list.`);
|
|
145
|
+
}
|
|
146
|
+
const sourceClient = buildS3Client({
|
|
147
|
+
mode: "prod",
|
|
148
|
+
endpoint: fromEndpoint ?? `https://s3.${fromRegion}.amazonaws.com`,
|
|
149
|
+
region: fromRegion,
|
|
150
|
+
accessKeyId: fromKey,
|
|
151
|
+
secretAccessKey: fromSecret,
|
|
152
|
+
forcePathStyle: !!fromEndpoint && !fromEndpoint.includes("amazonaws.com"),
|
|
153
|
+
buckets: { assets: { name: fromBucket, publicUrl: null } },
|
|
154
|
+
source: "migrate flags",
|
|
155
|
+
});
|
|
156
|
+
const prod = loadS3Config({ projectDir: flags.projectDir, mode: "prod" });
|
|
157
|
+
const target = endpoint(prod, flags.bucket, "prod");
|
|
158
|
+
if (!flags.dryRun)
|
|
159
|
+
await ensureBucket(target);
|
|
160
|
+
return runMirror({
|
|
161
|
+
label: `migrate ${fromBucket} → prod bucket "${target.bucket}"`,
|
|
162
|
+
flags,
|
|
163
|
+
run: () => mirror({
|
|
164
|
+
source: {
|
|
165
|
+
kind: "s3",
|
|
166
|
+
client: sourceClient,
|
|
167
|
+
bucket: fromBucket,
|
|
168
|
+
prefix: fromPrefix,
|
|
169
|
+
label: "external",
|
|
170
|
+
},
|
|
171
|
+
target,
|
|
172
|
+
dryRun: flags.dryRun,
|
|
173
|
+
onObject: makeProgress(flags.json),
|
|
174
|
+
}),
|
|
175
|
+
extra: { from: { bucket: fromBucket, endpoint: fromEndpoint, region: fromRegion } },
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// list — quick "what's in the bucket" probe
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
async function handleList(rawArgs, flags) {
|
|
182
|
+
const which = (rawArgs.find((a) => a === "dev" || a === "prod") ?? "dev");
|
|
183
|
+
const cfg = loadS3Config({ projectDir: flags.projectDir, mode: which });
|
|
184
|
+
const ep = endpoint(cfg, flags.bucket, which === "dev" ? "local" : "prod");
|
|
185
|
+
const out = await ep.client.send(new ListObjectsV2Command({ Bucket: ep.bucket, MaxKeys: 1000 }));
|
|
186
|
+
const entries = (out.Contents ?? []).map((c) => ({
|
|
187
|
+
key: c.Key ?? "",
|
|
188
|
+
size: c.Size ?? 0,
|
|
189
|
+
modified: c.LastModified?.toISOString(),
|
|
190
|
+
}));
|
|
191
|
+
if (flags.json) {
|
|
192
|
+
console.log(JSON.stringify({
|
|
193
|
+
ok: true,
|
|
194
|
+
mode: which,
|
|
195
|
+
bucket: ep.bucket,
|
|
196
|
+
endpoint: cfg.endpoint,
|
|
197
|
+
truncated: !!out.IsTruncated,
|
|
198
|
+
entries,
|
|
199
|
+
}, null, 2));
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
if (entries.length === 0) {
|
|
203
|
+
console.log(chalk.dim(` (empty) — ${ep.bucket} on ${cfg.endpoint}`));
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
for (const e of entries) {
|
|
207
|
+
console.log(` ${chalk.cyan(e.key.padEnd(60))} ${formatBytes(e.size).padStart(10)}`);
|
|
208
|
+
}
|
|
209
|
+
console.log(chalk.dim(`\n ${entries.length} object(s)${out.IsTruncated ? " (more — listing truncated)" : ""}`));
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// helpers
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
function endpoint(cfg, kind, label) {
|
|
216
|
+
const bucket = kind === "state" ? cfg.buckets.state?.name : cfg.buckets.assets.name;
|
|
217
|
+
if (!bucket) {
|
|
218
|
+
throw new Error(`No "${kind}" bucket configured for ${label} (${cfg.source}). ` +
|
|
219
|
+
`Either pick --bucket assets, or run \`hatchkit provision s3 --with-state-bucket\`.`);
|
|
220
|
+
}
|
|
221
|
+
return { kind: "s3", client: buildS3Client(cfg), bucket, label };
|
|
222
|
+
}
|
|
223
|
+
function makeProgress(json) {
|
|
224
|
+
if (json)
|
|
225
|
+
return undefined;
|
|
226
|
+
return (event) => {
|
|
227
|
+
if (event.kind === "copied") {
|
|
228
|
+
process.stdout.write(chalk.green(" ✓ ") + chalk.dim(event.key) + "\n");
|
|
229
|
+
}
|
|
230
|
+
else if (event.kind === "skipped") {
|
|
231
|
+
process.stdout.write(chalk.dim(` · ${event.key} (${event.reason})\n`));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
process.stdout.write(chalk.red(` ✗ ${event.key}: ${event.error.message}\n`));
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
async function runMirror(opts) {
|
|
239
|
+
if (opts.flags.dryRun && !opts.flags.json) {
|
|
240
|
+
console.log(chalk.yellow(` (dry run — no objects will be copied)`));
|
|
241
|
+
}
|
|
242
|
+
const spinner = opts.flags.json ? null : ora(opts.label).start();
|
|
243
|
+
spinner?.stop();
|
|
244
|
+
if (!opts.flags.json)
|
|
245
|
+
console.log(chalk.bold(` ${opts.label}`));
|
|
246
|
+
const result = await opts.run();
|
|
247
|
+
if (opts.flags.json) {
|
|
248
|
+
console.log(JSON.stringify({ ok: result.failed === 0, ...result, ...opts.extra }, null, 2));
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
const verb = opts.flags.dryRun ? "would copy" : "copied";
|
|
252
|
+
console.log(`\n ${chalk.bold(verb)} ${result.copied} · skipped ${result.skipped} · failed ${result.failed} · ${formatBytes(result.bytes)} · ${(result.durationMs / 1000).toFixed(1)}s`);
|
|
253
|
+
}
|
|
254
|
+
return result.failed === 0 ? 0 : 2;
|
|
255
|
+
}
|
|
256
|
+
function parseCommon(rest) {
|
|
257
|
+
const dirArg = takeFlag(rest, "--dir");
|
|
258
|
+
const bucketArg = takeFlag(rest, "--bucket") ?? "assets";
|
|
259
|
+
if (bucketArg !== "assets" && bucketArg !== "state") {
|
|
260
|
+
throw new Error(`--bucket must be "assets" or "state", got "${bucketArg}"`);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
projectDir: dirArg ? resolve(dirArg) : resolve("."),
|
|
264
|
+
bucket: bucketArg,
|
|
265
|
+
dryRun: rest.includes("--dry-run"),
|
|
266
|
+
json: rest.includes("--json"),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/** Pull `--flag value` (or `--flag=value`) out of rest, removing the
|
|
270
|
+
* matched tokens. Mutates `rest` so subsequent calls see a smaller
|
|
271
|
+
* argv. Mirrors the pattern used in cli/src/utils/flags.ts. */
|
|
272
|
+
function takeFlag(rest, name) {
|
|
273
|
+
for (let i = 0; i < rest.length; i++) {
|
|
274
|
+
const tok = rest[i];
|
|
275
|
+
if (tok === name) {
|
|
276
|
+
const v = rest[i + 1];
|
|
277
|
+
rest.splice(i, 2);
|
|
278
|
+
return v;
|
|
279
|
+
}
|
|
280
|
+
if (tok.startsWith(`${name}=`)) {
|
|
281
|
+
const v = tok.slice(name.length + 1);
|
|
282
|
+
rest.splice(i, 1);
|
|
283
|
+
return v;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
function printHelp() {
|
|
289
|
+
console.log(`
|
|
290
|
+
${chalk.bold("hatchkit assets")} — move bytes between local MinIO and prod buckets.
|
|
291
|
+
|
|
292
|
+
${chalk.bold("Subcommands")}
|
|
293
|
+
|
|
294
|
+
${chalk.cyan("seed")} [--from <dir>] Local dir → local MinIO bucket.
|
|
295
|
+
Defaults to ./seed/assets.
|
|
296
|
+
${chalk.cyan("push")} [--bucket assets|state] Local MinIO → prod bucket.
|
|
297
|
+
${chalk.cyan("pull")} [--bucket assets|state] Prod bucket → local MinIO.
|
|
298
|
+
Caution: prod data may include PII.
|
|
299
|
+
${chalk.cyan("migrate")} --from-endpoint=URL External S3 → prod bucket.
|
|
300
|
+
--from-bucket=NAME The adoption escape hatch.
|
|
301
|
+
--from-key=AKIA… Creds can also come from
|
|
302
|
+
--from-secret=… HATCHKIT_FROM_ACCESS_KEY_ID +
|
|
303
|
+
[--from-region=us-east-1] HATCHKIT_FROM_SECRET_ACCESS_KEY.
|
|
304
|
+
[--from-prefix=path/]
|
|
305
|
+
${chalk.cyan("list")} [dev|prod] [--bucket assets|state]
|
|
306
|
+
Show what's in a bucket.
|
|
307
|
+
|
|
308
|
+
${chalk.bold("Common flags")}
|
|
309
|
+
|
|
310
|
+
--dir <path> Project dir (defaults to cwd).
|
|
311
|
+
--bucket KIND "assets" (default) or "state".
|
|
312
|
+
--dry-run Plan only — list what would be copied.
|
|
313
|
+
--json Machine-readable output.
|
|
314
|
+
|
|
315
|
+
${chalk.bold("Notes")}
|
|
316
|
+
|
|
317
|
+
Mirror semantics: copy missing + changed objects. Never deletes from
|
|
318
|
+
the target. ETag mismatches always re-copy (false positives are
|
|
319
|
+
wasted bandwidth, not data loss). Streams Get→Put so cross-provider
|
|
320
|
+
migrations (e.g. AWS → R2) work without server-side copy.
|
|
321
|
+
|
|
322
|
+
Reads dev creds from packages/server/.env.development (plaintext) and
|
|
323
|
+
prod creds from packages/server/.env.production (decrypted via
|
|
324
|
+
dotenvx + .env.keys). Bucket names come from .hatchkit.json when
|
|
325
|
+
the env doesn't carry them (R2's URL-driven assets bucket).
|
|
326
|
+
`);
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
2
|
+
import type { ResolvedS3Config } from "./env.js";
|
|
3
|
+
/** Build an SDK client from our normalised config. */
|
|
4
|
+
export declare function buildS3Client(cfg: ResolvedS3Config): S3Client;
|
|
5
|
+
export interface MirrorEndpointS3 {
|
|
6
|
+
kind: "s3";
|
|
7
|
+
client: S3Client;
|
|
8
|
+
bucket: string;
|
|
9
|
+
/** Optional prefix to scope the source to a sub-tree. */
|
|
10
|
+
prefix?: string;
|
|
11
|
+
/** Human-readable label for log output (e.g. "prod", "local"). */
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
export interface MirrorEndpointDir {
|
|
15
|
+
kind: "dir";
|
|
16
|
+
/** Local directory; entries are walked recursively. */
|
|
17
|
+
dir: string;
|
|
18
|
+
/** Optional prefix to prepend to all uploaded keys. */
|
|
19
|
+
prefix?: string;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
export type MirrorSource = MirrorEndpointS3 | MirrorEndpointDir;
|
|
23
|
+
export interface MirrorOptions {
|
|
24
|
+
source: MirrorSource;
|
|
25
|
+
target: MirrorEndpointS3;
|
|
26
|
+
/** When true, list what would be copied but don't transfer. */
|
|
27
|
+
dryRun?: boolean;
|
|
28
|
+
/** Max concurrent uploads. Defaults to 8. */
|
|
29
|
+
concurrency?: number;
|
|
30
|
+
/** Optional progress callback fired per object. */
|
|
31
|
+
onObject?: (event: ObjectEvent) => void;
|
|
32
|
+
}
|
|
33
|
+
export type ObjectEvent = {
|
|
34
|
+
kind: "skipped";
|
|
35
|
+
key: string;
|
|
36
|
+
reason: "etag-match" | "size-match";
|
|
37
|
+
} | {
|
|
38
|
+
kind: "copied";
|
|
39
|
+
key: string;
|
|
40
|
+
bytes: number;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "copy-failed";
|
|
43
|
+
key: string;
|
|
44
|
+
error: Error;
|
|
45
|
+
};
|
|
46
|
+
export interface MirrorResult {
|
|
47
|
+
scanned: number;
|
|
48
|
+
copied: number;
|
|
49
|
+
skipped: number;
|
|
50
|
+
failed: number;
|
|
51
|
+
bytes: number;
|
|
52
|
+
durationMs: number;
|
|
53
|
+
}
|
|
54
|
+
export declare function mirror(opts: MirrorOptions): Promise<MirrorResult>;
|
|
55
|
+
/** Verify the target bucket actually exists + is reachable. Surfaces
|
|
56
|
+
* a friendlier error than the SDK's stack-traced NoSuchBucket. */
|
|
57
|
+
export declare function ensureBucket(endpoint: MirrorEndpointS3): Promise<void>;
|
|
58
|
+
export declare function formatBytes(n: number): string;
|
|
59
|
+
//# sourceMappingURL=mirror.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirror.d.ts","sourceRoot":"","sources":["../../src/assets/mirror.ts"],"names":[],"mappings":"AA2BA,OAAO,EAKL,QAAQ,EACT,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,CAW7D;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAwDvE;AA8HD;mEACmE;AACnE,wBAAsB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa5E;AA4BD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK7C"}
|