ninedeploy 0.18.26 → 0.18.28

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 (74) hide show
  1. package/dist/commands/databaseUpgrade.d.ts +27 -0
  2. package/dist/commands/databaseUpgrade.d.ts.map +1 -0
  3. package/dist/commands/databaseUpgrade.js +151 -0
  4. package/dist/commands/databaseUpgrade.js.map +1 -0
  5. package/dist/commands/importApply.d.ts +114 -0
  6. package/dist/commands/importApply.d.ts.map +1 -0
  7. package/dist/commands/importApply.js +403 -0
  8. package/dist/commands/importApply.js.map +1 -0
  9. package/dist/commands/importCutover.d.ts +95 -0
  10. package/dist/commands/importCutover.d.ts.map +1 -0
  11. package/dist/commands/importCutover.js +293 -0
  12. package/dist/commands/importCutover.js.map +1 -0
  13. package/dist/commands/importData.d.ts +60 -0
  14. package/dist/commands/importData.d.ts.map +1 -0
  15. package/dist/commands/importData.js +286 -0
  16. package/dist/commands/importData.js.map +1 -0
  17. package/dist/commands/importPlan.d.ts +32 -0
  18. package/dist/commands/importPlan.d.ts.map +1 -0
  19. package/dist/commands/importPlan.js +138 -0
  20. package/dist/commands/importPlan.js.map +1 -0
  21. package/dist/commands/importVolumes.d.ts +38 -0
  22. package/dist/commands/importVolumes.d.ts.map +1 -0
  23. package/dist/commands/importVolumes.js +161 -0
  24. package/dist/commands/importVolumes.js.map +1 -0
  25. package/dist/index.js +59 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/importers/caprover.d.ts +13 -0
  28. package/dist/lib/importers/caprover.d.ts.map +1 -0
  29. package/dist/lib/importers/caprover.js +150 -0
  30. package/dist/lib/importers/caprover.js.map +1 -0
  31. package/dist/lib/importers/connections.d.ts +39 -0
  32. package/dist/lib/importers/connections.d.ts.map +1 -0
  33. package/dist/lib/importers/connections.js +119 -0
  34. package/dist/lib/importers/connections.js.map +1 -0
  35. package/dist/lib/importers/coolify.d.ts +10 -0
  36. package/dist/lib/importers/coolify.d.ts.map +1 -0
  37. package/dist/lib/importers/coolify.js +174 -0
  38. package/dist/lib/importers/coolify.js.map +1 -0
  39. package/dist/lib/importers/dokploy.d.ts +13 -0
  40. package/dist/lib/importers/dokploy.d.ts.map +1 -0
  41. package/dist/lib/importers/dokploy.js +183 -0
  42. package/dist/lib/importers/dokploy.js.map +1 -0
  43. package/dist/lib/importers/heroku.d.ts +50 -0
  44. package/dist/lib/importers/heroku.d.ts.map +1 -0
  45. package/dist/lib/importers/heroku.js +159 -0
  46. package/dist/lib/importers/heroku.js.map +1 -0
  47. package/dist/lib/importers/plan.d.ts +137 -0
  48. package/dist/lib/importers/plan.d.ts.map +1 -0
  49. package/dist/lib/importers/plan.js +110 -0
  50. package/dist/lib/importers/plan.js.map +1 -0
  51. package/dist/lib/importers/shell.d.ts +24 -0
  52. package/dist/lib/importers/shell.d.ts.map +1 -0
  53. package/dist/lib/importers/shell.js +45 -0
  54. package/dist/lib/importers/shell.js.map +1 -0
  55. package/dist/lib/importers/sources.d.ts +26 -0
  56. package/dist/lib/importers/sources.d.ts.map +1 -0
  57. package/dist/lib/importers/sources.js +100 -0
  58. package/dist/lib/importers/sources.js.map +1 -0
  59. package/package.json +3 -3
  60. package/src/commands/databaseUpgrade.ts +144 -0
  61. package/src/commands/importApply.ts +445 -0
  62. package/src/commands/importCutover.ts +329 -0
  63. package/src/commands/importData.ts +302 -0
  64. package/src/commands/importPlan.ts +143 -0
  65. package/src/commands/importVolumes.ts +168 -0
  66. package/src/index.ts +61 -0
  67. package/src/lib/importers/caprover.ts +141 -0
  68. package/src/lib/importers/connections.ts +133 -0
  69. package/src/lib/importers/coolify.ts +164 -0
  70. package/src/lib/importers/dokploy.ts +167 -0
  71. package/src/lib/importers/heroku.ts +168 -0
  72. package/src/lib/importers/plan.ts +209 -0
  73. package/src/lib/importers/shell.ts +56 -0
  74. package/src/lib/importers/sources.ts +96 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * A1: an import plan from a Heroku app's own files: `app.json` and the
3
+ * `Procfile` in a checkout of its repository. No Heroku API and no
4
+ * credential: the mapping follows Heroku's documented formats
5
+ * (devcenter: app-json-schema, procfile).
6
+ *
7
+ * - Every Procfile process except `release` becomes a service built from the
8
+ * repository with Nixpacks, whose start command is that process's line.
9
+ * Nixpacks is the build pack that honours a per-service start command, runs
10
+ * it through a shell (so `$PORT` expands) and sets PORT to the service port
11
+ * (checked live on a NineDeploy panel; the heroku/paketo buildpacks and
12
+ * Dockerfile builds ignore the start command).
13
+ * - A process other than `web` gets the `running` health check (it answers
14
+ * no HTTP), no port routing and no domain.
15
+ * - `release` is not mapped to NineDeploy's pre-deploy hook, which runs in
16
+ * the panel's own container before the build, without a shell (checked
17
+ * live). Nixpacks itself runs the Procfile's release line as a build step
18
+ * of every service built from the repository, with the attached
19
+ * DATABASE_URL (checked live), so it is flagged with what that means.
20
+ * - Nixpacks reads the Procfile itself, as YAML: a line with `: ` inside its
21
+ * command fails the build (checked live), so such lines are flagged.
22
+ * - `heroku-postgresql` and `heroku-redis` add-ons become databases attached
23
+ * to every service under DATABASE_URL / REDIS_URL, as Heroku sets them.
24
+ * - Config var names come from app.json `env`; values only ever come from a
25
+ * .env file at apply time (`heroku config --shell`).
26
+ */
27
+ import { emptyPlan } from './plan.js';
28
+ import { isPlainName } from './shell.js';
29
+ const obj = (v) => (v && typeof v === 'object' && !Array.isArray(v) ? v : {});
30
+ const str = (v) => (typeof v === 'string' && v.trim() ? v.trim() : undefined);
31
+ /** Procfile process types in file order: `<type>: <command>` lines. */
32
+ export function parseProcfile(content) {
33
+ const out = [];
34
+ for (const line of content.split(/\r?\n/)) {
35
+ const m = /^([A-Za-z0-9_-]+):\s*(.+?)\s*$/.exec(line);
36
+ if (m && !out.some((p) => p.type === m[1]))
37
+ out.push({ type: m[1], command: m[2] });
38
+ }
39
+ return out;
40
+ }
41
+ /** Add-ons NineDeploy runs itself, and the variable Heroku sets for each. */
42
+ const ADDONS = {
43
+ 'heroku-postgresql': { engine: 'postgres', env: 'DATABASE_URL' },
44
+ 'heroku-redis': { engine: 'redis', env: 'REDIS_URL' },
45
+ };
46
+ const slugName = (s) => s.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60) || 'app';
47
+ export function planFromHeroku(files, opts) {
48
+ if (files.appJson === undefined && files.procfile === undefined) {
49
+ throw new Error('Neither app.json nor a Procfile was found: point --dir at a checkout of the Heroku app\'s repository.');
50
+ }
51
+ let app = {};
52
+ if (files.appJson !== undefined) {
53
+ try {
54
+ app = obj(JSON.parse(files.appJson));
55
+ }
56
+ catch {
57
+ throw new Error('app.json is not valid JSON.');
58
+ }
59
+ }
60
+ const base = slugName(str(app['name']) ?? opts.dirName);
61
+ const herokuApp = opts.app && isPlainName(opts.app) ? opts.app : undefined;
62
+ const plan = emptyPlan('heroku', opts.repoUrl, null, `the app.json and Procfile of ${opts.repoUrl}@${opts.branch}`);
63
+ plan.notes.push('Heroku mapping: it follows Heroku\'s documented app.json and Procfile formats; no Heroku API is read.');
64
+ // Add-ons → databases.
65
+ const shared = [];
66
+ const attachments = [];
67
+ for (const raw of Array.isArray(app['addons']) ? app['addons'] : []) {
68
+ const plan_ = typeof raw === 'string' ? raw : str(obj(raw)['plan']);
69
+ if (!plan_)
70
+ continue;
71
+ const service = plan_.split(':')[0];
72
+ const known = ADDONS[service];
73
+ if (!known) {
74
+ shared.push({ level: 'unsupported', option: 'addon', detail: `${plan_} has no NineDeploy equivalent; run it elsewhere and set its variables by hand.` });
75
+ continue;
76
+ }
77
+ if (plan.databases.some((d) => d.engine === known.engine))
78
+ continue;
79
+ const ref = `${base}-${known.engine}`;
80
+ const issues = [
81
+ { level: 'manual', option: 'data', detail: 'Data is not moved by this step: create the database, then restore a dump into it (step 3).' },
82
+ ];
83
+ if (known.engine === 'postgres') {
84
+ issues.push({ level: 'manual', option: 'ssl', detail: 'Heroku Postgres requires SSL, so apps often force it in code (sslmode=require, ssl_require=True). The NineDeploy database is reached over the internal Docker network, which has no TLS: drop that requirement for this connection.' });
85
+ }
86
+ const db = { ref, name: ref, engine: known.engine, image: null, issues };
87
+ if (herokuApp)
88
+ db.runtime = { kind: 'heroku-app', name: herokuApp };
89
+ plan.databases.push(db);
90
+ attachments.push({ database: ref, envAlias: known.env });
91
+ }
92
+ if (plan.databases.length && !herokuApp) {
93
+ shared.push({ level: 'info', option: 'app', detail: 'Pass --app <heroku app name> to get a ready pg:backups command in import data.' });
94
+ }
95
+ // Config vars → names.
96
+ const env = [];
97
+ for (const [key, v] of Object.entries(obj(app['env']))) {
98
+ if (attachments.some((a) => a.envAlias === key))
99
+ continue;
100
+ env.push({ key });
101
+ if (obj(v)['generator'] === 'secret')
102
+ shared.push({ level: 'manual', option: 'env', detail: `${key} is generated on Heroku (generator: secret): put its current value in the .env file, or a new random one.` });
103
+ }
104
+ // Build notes.
105
+ const buildpacks = Array.isArray(app['buildpacks']) ? app['buildpacks'].map((b) => str(obj(b)['url']) ?? '').filter(Boolean) : [];
106
+ if (buildpacks.length) {
107
+ shared.push({ level: 'info', option: 'buildpacks', detail: `Built with Nixpacks, which detects the language itself; ${buildpacks.join(', ')} ${buildpacks.length === 1 ? 'is' : 'are'} not used. Add a nixpacks.toml if detection differs.` });
108
+ }
109
+ if (files.herokuYml)
110
+ shared.push({ level: 'manual', option: 'heroku.yml', detail: 'heroku.yml builds a container: set the build pack to Dockerfile and its path under Service → Settings.' });
111
+ if (str(obj(app['scripts'])['postdeploy'])) {
112
+ shared.push({ level: 'manual', option: 'postdeploy', detail: 'scripts.postdeploy runs once on Heroku after the app is created: run it by hand after the first deploy (it is not a per-deploy hook).' });
113
+ }
114
+ const formation = obj(app['formation']);
115
+ const procs = files.procfile !== undefined ? parseProcfile(files.procfile) : [];
116
+ const release = procs.find((p) => p.type === 'release');
117
+ const runnable = procs.filter((p) => p.type !== 'release');
118
+ if (runnable.length === 0)
119
+ runnable.push({ type: 'web', command: '' });
120
+ for (const p of runnable) {
121
+ const isWeb = p.type === 'web';
122
+ const name = isWeb ? base : `${base}-${slugName(p.type)}`;
123
+ const issues = [...shared];
124
+ const create = {
125
+ name, type: 'docker', repoUrl: opts.repoUrl, branch: opts.branch,
126
+ build: { buildPack: 'nixpacks', ...(p.command ? { startCmd: p.command } : {}) },
127
+ };
128
+ if (isWeb) {
129
+ create.port = 5000;
130
+ issues.push({ level: 'info', option: 'PORT', detail: 'NineDeploy sets PORT to the service port (5000) for a Nixpacks build, as Heroku sets $PORT.' });
131
+ if (release) {
132
+ issues.push({ level: 'manual', option: 'release', detail: `Nixpacks runs the Procfile's release line ("${release.command}") as a build step of every service built from this repository, with the attached DATABASE_URL, so it runs before each deploy of each of them, not once. Make sure that is safe (a migration usually is), or take it out of the Procfile and run it by hand. A $VARIABLE in it is built into the image with its value (the deploy log masks secret values).` });
133
+ }
134
+ }
135
+ if (!p.command)
136
+ issues.push({ level: 'info', option: 'Procfile', detail: 'No Procfile: Nixpacks picks the start command.' });
137
+ if (/: /.test(p.command))
138
+ issues.push({ level: 'manual', option: 'Procfile', detail: 'Nixpacks reads the Procfile as YAML, and ": " inside this command breaks it: quote the command in the Procfile, or the build fails.' });
139
+ const q = Number(obj(formation[p.type])['quantity']);
140
+ if (Number.isInteger(q) && q > 1)
141
+ create.replicas = Math.min(q, 10);
142
+ if (Number.isInteger(q) && q > 10)
143
+ issues.push({ level: 'manual', option: 'formation', detail: `${q} dynos; NineDeploy runs at most 10 replicas of a service.` });
144
+ if (Number.isInteger(q) && q === 0)
145
+ issues.push({ level: 'info', option: 'formation', detail: 'Scaled to 0 on Heroku; NineDeploy runs one when it deploys the service.' });
146
+ const size = str(obj(formation[p.type])['size']);
147
+ if (size)
148
+ issues.push({ level: 'info', option: 'size', detail: `Dyno size ${size}: set a memory limit under Service → Settings if you need one.` });
149
+ const svc = { ref: p.type, name, kind: 'git', create, domains: [], env: [...env], volumes: [], issues };
150
+ if (!isWeb)
151
+ svc.settings = { healthCheck: 'running' };
152
+ if (attachments.length)
153
+ svc.attachments = attachments.map((a) => ({ ...a }));
154
+ plan.services.push(svc);
155
+ }
156
+ plan.notes.push('Domains are not in app.json: add them with import cutover after editing the plan, or under Service → Domains.');
157
+ return plan;
158
+ }
159
+ //# sourceMappingURL=heroku.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heroku.js","sourceRoot":"","sources":["../../../src/lib/importers/heroku.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * A1 step 1 (docs/plans/COMPETITIVE_ROADMAP_2026-11.md): a read-only import
3
+ * plan. An adapter reads another platform's API (Coolify, Dokploy, CapRover)
4
+ * and describes, per item, what NineDeploy would create, what it cannot carry,
5
+ * and what needs a person. Nothing is created and the source is not changed.
6
+ *
7
+ * Secret hygiene is part of the type: a plan carries environment variable
8
+ * NAMES only, never values, passwords, tokens or keys, and every URL has its
9
+ * userinfo removed before it enters the plan. Step 2 (`import apply`, in
10
+ * commands/importApply.ts) takes values only from .env files the person passes.
11
+ */
12
+ import type { CreateService } from '@ninedeploy/schemas';
13
+ export type SourceKind = 'coolify' | 'dokploy' | 'caprover' | 'heroku';
14
+ /** GET a JSON path on the source panel (auth already applied). */
15
+ export type SourceGet = (path: string) => Promise<unknown>;
16
+ export type IssueLevel = 'unsupported' | 'manual' | 'info';
17
+ export interface PlanIssue {
18
+ level: IssueLevel;
19
+ /** The source option or field the issue is about, e.g. `build_pack`. */
20
+ option: string;
21
+ detail: string;
22
+ }
23
+ /** The createService fields a step-2 apply would send (subset, never secrets). */
24
+ export type ServiceCreateFields = Pick<CreateService, 'name' | 'type'> & Partial<Pick<CreateService, 'image' | 'repoUrl' | 'branch' | 'port' | 'publishedPort' | 'replicas' | 'cpuLimitMilli' | 'memLimitMb' | 'healthPath' | 'volumeMount'>> & {
25
+ build?: {
26
+ buildPack?: NonNullable<CreateService['build']>['buildPack'];
27
+ baseDir?: string;
28
+ dockerfilePath?: string;
29
+ outputDir?: string;
30
+ startCmd?: string;
31
+ };
32
+ };
33
+ /**
34
+ * A domain of a service. `sourceDefault` marks a host the source generated
35
+ * for itself (CapRover's <app>.<root domain>, Coolify's sslip.io, Dokploy's
36
+ * traefik.me): it stays with the source and is never added to NineDeploy.
37
+ * Optional and additive, so planVersion stays 1.
38
+ */
39
+ export interface PlanDomain {
40
+ host: string;
41
+ https: boolean;
42
+ sourceDefault?: true;
43
+ }
44
+ /** Wildcard-DNS hosts the sources generate (they resolve to an IP in the name, or to the source). */
45
+ export declare function isGeneratedHost(host: string): boolean;
46
+ export declare function planDomain(host: string, https: boolean, sourceDefault?: boolean): PlanDomain;
47
+ export interface PlanService {
48
+ /** Stable reference in the source (uuid / id / appName). */
49
+ ref: string;
50
+ name: string;
51
+ kind: 'image' | 'git' | 'compose';
52
+ create: ServiceCreateFields;
53
+ domains: PlanDomain[];
54
+ /** Names only. `secret` marks values the source keeps hidden or flags as secret. */
55
+ env: Array<{
56
+ key: string;
57
+ }>;
58
+ volumes: Array<{
59
+ mountPath: string;
60
+ source: 'volume' | 'bind' | 'file';
61
+ name?: string;
62
+ }>;
63
+ issues: PlanIssue[];
64
+ /**
65
+ * Where it runs on the source host, for the volume command of `import
66
+ * data` (same shape as PlanDatabase.runtime). Optional and additive.
67
+ */
68
+ runtime?: PlanRuntime;
69
+ /** Settings apply sets right after create (an update; not create fields). Optional and additive. */
70
+ settings?: {
71
+ healthCheck?: 'running';
72
+ };
73
+ /** Databases of the plan to attach under a variable (Heroku add-ons). Optional and additive. */
74
+ attachments?: Array<{
75
+ database: string;
76
+ envAlias: string;
77
+ }>;
78
+ }
79
+ /**
80
+ * Where an item runs on the source: a container, a Swarm service, or (Heroku
81
+ * add-ons) the Heroku app that owns it. Every reader switches on `kind`.
82
+ */
83
+ export type PlanRuntime = {
84
+ kind: 'container' | 'swarm-service' | 'heroku-app';
85
+ name: string;
86
+ };
87
+ export type PlanEngine = 'postgres' | 'mysql' | 'mariadb' | 'mongo' | 'redis' | 'keydb' | 'dragonfly' | 'clickhouse';
88
+ export interface PlanDatabase {
89
+ ref: string;
90
+ name: string;
91
+ /** NineDeploy engine, or null when NineDeploy has no managed equivalent. */
92
+ engine: PlanEngine | null;
93
+ /** The source image (the version lives in its tag), when the source says. */
94
+ image: string | null;
95
+ /**
96
+ * Where it runs on the source host, for the dump commands of `import data`:
97
+ * a plain container name, or a Swarm service whose task container is found
98
+ * by its com.docker.swarm.service.name label. Optional and additive.
99
+ */
100
+ runtime?: PlanRuntime;
101
+ issues: PlanIssue[];
102
+ }
103
+ export interface ImportPlan {
104
+ planVersion: 1;
105
+ source: {
106
+ kind: SourceKind;
107
+ url: string;
108
+ version: string | null;
109
+ scope: string;
110
+ };
111
+ generatedAt: string;
112
+ services: PlanService[];
113
+ databases: PlanDatabase[];
114
+ /** Plan-wide notes (scope limits, what step 1 does not do). */
115
+ notes: string[];
116
+ }
117
+ /** Always present: what this plan is and is not. */
118
+ export declare const PLAN_NOTES: string[];
119
+ /** Remove `user:password@` from a URL; non-URLs pass through unchanged. */
120
+ export declare function stripUserinfo(raw: string): string;
121
+ /** `KEY=VALUE` lines (Dokploy's env blob) → names only. Comments and blanks skipped. */
122
+ export declare function envNames(blob: string | null | undefined): Array<{
123
+ key: string;
124
+ }>;
125
+ /** Each URL or bare host in a list → `{host, https}` (Coolify's comma-separated `fqdn`). */
126
+ export declare function domainsFrom(list: string | null | undefined): PlanDomain[];
127
+ /** "512M" / "2g" / "1024" (bytes or MB per source) → megabytes, or undefined. */
128
+ export declare function memToMb(raw: string | number | null | undefined, plainUnit?: 'bytes' | 'mb'): number | undefined;
129
+ /** "1.5" cores → 1500 millicores, or undefined. */
130
+ export declare function cpusToMilli(raw: string | number | null | undefined): number | undefined;
131
+ /** NineDeploy accepts 1..10 replicas. */
132
+ export declare function replicasFor(raw: unknown, issues: PlanIssue[]): number | undefined;
133
+ /** The first volume becomes `volumeMount`; any others are listed for a person. */
134
+ export declare function firstVolumeMount(volumes: PlanService['volumes'], issues: PlanIssue[]): string | undefined;
135
+ export declare const DATA_NOT_MOVED: PlanIssue;
136
+ export declare function emptyPlan(kind: SourceKind, url: string, version: string | null, scope: string): ImportPlan;
137
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/lib/importers/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /** Wildcard-DNS hosts the sources generate (they resolve to an IP in the name, or to the source). */
2
+ export function isGeneratedHost(host) {
3
+ return /\.(sslip\.io|nip\.io|traefik\.me)$/i.test(host);
4
+ }
5
+ export function planDomain(host, https, sourceDefault = isGeneratedHost(host)) {
6
+ return sourceDefault ? { host, https, sourceDefault: true } : { host, https };
7
+ }
8
+ /** Always present: what this plan is and is not. */
9
+ export const PLAN_NOTES = [
10
+ 'Read-only: nothing was created here and nothing was changed on the source.',
11
+ 'Environment variables are listed by name only. Values, passwords, tokens and keys are never written to a plan.',
12
+ 'Database contents and volume data are not moved by this step.',
13
+ ];
14
+ /** Remove `user:password@` from a URL; non-URLs pass through unchanged. */
15
+ export function stripUserinfo(raw) {
16
+ // Only `scheme://` strings are URLs here: `user:secret@host:repo` would
17
+ // otherwise parse as scheme "user:" and keep its password.
18
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) {
19
+ try {
20
+ const u = new URL(raw);
21
+ if (!u.username && !u.password)
22
+ return raw;
23
+ u.username = '';
24
+ u.password = '';
25
+ return u.toString();
26
+ }
27
+ catch {
28
+ /* fall through to the textual rule */
29
+ }
30
+ }
31
+ // scp-style remotes: `git@host:owner/repo.git` (no password) stays as it is;
32
+ // `user:secret@host…` loses its credentials.
33
+ return raw.replace(/^[^@/\s]+:[^@/\s]*@/, '');
34
+ }
35
+ /** `KEY=VALUE` lines (Dokploy's env blob) → names only. Comments and blanks skipped. */
36
+ export function envNames(blob) {
37
+ const out = [];
38
+ for (const line of (blob ?? '').split(/\r?\n/)) {
39
+ const t = line.trim();
40
+ if (!t || t.startsWith('#'))
41
+ continue;
42
+ const eq = t.indexOf('=');
43
+ const key = (eq === -1 ? t : t.slice(0, eq)).replace(/^export\s+/, '').trim();
44
+ if (/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key))
45
+ out.push({ key });
46
+ }
47
+ return out;
48
+ }
49
+ /** Each URL or bare host in a list → `{host, https}` (Coolify's comma-separated `fqdn`). */
50
+ export function domainsFrom(list) {
51
+ const out = [];
52
+ for (const part of (list ?? '').split(',')) {
53
+ const t = part.trim();
54
+ if (!t)
55
+ continue;
56
+ try {
57
+ const u = new URL(/^[a-z]+:\/\//i.test(t) ? t : `http://${t}`);
58
+ if (u.hostname)
59
+ out.push(planDomain(u.hostname, u.protocol === 'https:'));
60
+ }
61
+ catch {
62
+ /* not a host */
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ /** "512M" / "2g" / "1024" (bytes or MB per source) → megabytes, or undefined. */
68
+ export function memToMb(raw, plainUnit = 'bytes') {
69
+ if (raw == null || raw === '' || raw === '0' || raw === 0)
70
+ return undefined;
71
+ const m = /^(\d+(?:\.\d+)?)\s*([kmgt]?)b?$/i.exec(String(raw).trim());
72
+ if (!m)
73
+ return undefined;
74
+ const n = Number(m[1]);
75
+ const unit = (m[2] ?? '').toLowerCase();
76
+ const mb = unit === 'k' ? n / 1024 : unit === 'm' ? n : unit === 'g' ? n * 1024 : unit === 't' ? n * 1024 * 1024 : plainUnit === 'mb' ? n : n / (1024 * 1024);
77
+ return mb >= 1 ? Math.round(mb) : undefined;
78
+ }
79
+ /** "1.5" cores → 1500 millicores, or undefined. */
80
+ export function cpusToMilli(raw) {
81
+ const n = Number(raw);
82
+ return Number.isFinite(n) && n > 0 ? Math.round(n * 1000) : undefined;
83
+ }
84
+ /** NineDeploy accepts 1..10 replicas. */
85
+ export function replicasFor(raw, issues) {
86
+ const n = Number(raw);
87
+ if (!Number.isInteger(n) || n <= 1)
88
+ return undefined;
89
+ if (n > 10) {
90
+ issues.push({ level: 'manual', option: 'replicas', detail: `${n} replicas in the source; NineDeploy runs at most 10 per service, so the plan uses 10.` });
91
+ return 10;
92
+ }
93
+ return n;
94
+ }
95
+ /** The first volume becomes `volumeMount`; any others are listed for a person. */
96
+ export function firstVolumeMount(volumes, issues) {
97
+ const named = volumes.filter((v) => v.source !== 'file');
98
+ if (named.length > 1) {
99
+ issues.push({ level: 'manual', option: 'volumes', detail: `${named.length} volumes; a new service gets one at create time (${named[0].mountPath}). Attach the others under Volumes & Storage.` });
100
+ }
101
+ for (const f of volumes.filter((v) => v.source === 'file')) {
102
+ issues.push({ level: 'manual', option: 'file mount', detail: `File mount ${f.mountPath}: recreate it under Service → File mounts (its content is not read).` });
103
+ }
104
+ return named[0]?.mountPath;
105
+ }
106
+ export const DATA_NOT_MOVED = { level: 'manual', option: 'data', detail: 'Data is not moved by this step: create the database, then restore a dump into it (step 3).' };
107
+ export function emptyPlan(kind, url, version, scope) {
108
+ return { planVersion: 1, source: { kind, url: stripUserinfo(url), version, scope }, generatedAt: new Date().toISOString(), services: [], databases: [], notes: [...PLAN_NOTES] };
109
+ }
110
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/lib/importers/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Pieces of the commands `import data` prints for the source host. The names
3
+ * in them come from the source platform's API, and the person pastes the
4
+ * command into a shell, so a name only goes in when it is a plain Docker
5
+ * name; anything else becomes a placeholder to fill in by hand.
6
+ */
7
+ import type { PlanRuntime } from './plan.js';
8
+ export declare const isPlainName: (name: string) => boolean;
9
+ /** Single-quote for POSIX sh. */
10
+ export declare const shellQuote: (s: string) => string;
11
+ /** A file name made of safe characters only. */
12
+ export declare function fileBase(name: string): string;
13
+ /**
14
+ * The container to reach on the source host: a container name, or the newest
15
+ * task container of a Swarm service (`all` also finds stopped ones). A
16
+ * missing or unusual name gives `<container>` and a note saying so.
17
+ */
18
+ export declare function sourceTarget(runtime: PlanRuntime | undefined, what: string, all?: boolean): {
19
+ target: string;
20
+ note: string | null;
21
+ };
22
+ /** `<name>=<file>` for a --dump / --volume flag, quoted when the name is not plain. */
23
+ export declare function flagArg(name: string, file: string): string;
24
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/lib/importers/shell.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAK7C,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,OAAiC,CAAC;AAE7E,iCAAiC;AACjC,eAAO,MAAM,UAAU,MAAO,MAAM,KAAG,MAAyC,CAAC;AAEjF,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,IAAI,EAAE,MAAM,EACZ,GAAG,UAAQ,GACV;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAkBzC;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pieces of the commands `import data` prints for the source host. The names
3
+ * in them come from the source platform's API, and the person pastes the
4
+ * command into a shell, so a name only goes in when it is a plain Docker
5
+ * name; anything else becomes a placeholder to fill in by hand.
6
+ */
7
+ /** A Docker container or service name: no spaces, quotes, `$`, `;` or other shell syntax. */
8
+ const DOCKER_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,254}$/;
9
+ export const isPlainName = (name) => DOCKER_NAME.test(name);
10
+ /** Single-quote for POSIX sh. */
11
+ export const shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
12
+ /** A file name made of safe characters only. */
13
+ export function fileBase(name) {
14
+ const safe = name.replace(/[^A-Za-z0-9_.-]/g, '_').replace(/^[.-]+/, '_');
15
+ return safe || 'import';
16
+ }
17
+ /**
18
+ * The container to reach on the source host: a container name, or the newest
19
+ * task container of a Swarm service (`all` also finds stopped ones). A
20
+ * missing or unusual name gives `<container>` and a note saying so.
21
+ */
22
+ export function sourceTarget(runtime, what, all = false) {
23
+ if (runtime && isPlainName(runtime.name)) {
24
+ switch (runtime.kind) {
25
+ case 'container':
26
+ return { target: runtime.name, note: null };
27
+ case 'swarm-service':
28
+ return { target: `$(docker ps -${all ? 'a' : ''}q --filter label=com.docker.swarm.service.name=${runtime.name} | head -n 1)`, note: null };
29
+ case 'heroku-app':
30
+ // A Heroku app has no container on a host you run docker on.
31
+ return { target: '<container>', note: `Replace <container> with ${what}; Heroku runs it, so there is no docker host to read it from.` };
32
+ default: {
33
+ const never = runtime.kind;
34
+ return never;
35
+ }
36
+ }
37
+ }
38
+ const why = runtime ? ` (its name on the source, ${JSON.stringify(runtime.name)}, is not a plain Docker name, so it is not put in a shell command)` : '';
39
+ return { target: '<container>', note: `Replace <container> with ${what} on the source host (docker ps${all ? ' -a' : ''})${why}.` };
40
+ }
41
+ /** `<name>=<file>` for a --dump / --volume flag, quoted when the name is not plain. */
42
+ export function flagArg(name, file) {
43
+ return isPlainName(name) ? `${name}=${file}` : shellQuote(`${name}=${file}`);
44
+ }
45
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/lib/importers/shell.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,6FAA6F;AAC7F,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAE7E,iCAAiC;AACjC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAEjF,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1E,OAAO,IAAI,IAAI,QAAQ,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAgC,EAChC,IAAY,EACZ,GAAG,GAAG,KAAK;IAEX,IAAI,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,WAAW;gBACd,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC9C,KAAK,eAAe;gBAClB,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,kDAAkD,OAAO,CAAC,IAAI,eAAe,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAC7I,KAAK,YAAY;gBACf,6DAA6D;gBAC7D,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,4BAA4B,IAAI,+DAA+D,EAAE,CAAC;YAC1I,SAAS,CAAC;gBACR,MAAM,KAAK,GAAU,OAAO,CAAC,IAAI,CAAC;gBAClC,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,6BAA6B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzJ,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,4BAA4B,IAAI,iCAAiC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,GAAG,EAAE,CAAC;AACtI,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAY;IAChD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * HTTP clients for the import sources (A1 step 1). Native fetch only. The
3
+ * credentials come from the caller (an env var or a hidden prompt, never
4
+ * argv) and never appear in an error message.
5
+ */
6
+ import type { SourceGet } from './plan.js';
7
+ export declare class SourceError extends Error {
8
+ }
9
+ /** CapRover asked for a two-factor code (status 1114). */
10
+ export declare class OtpRequiredError extends SourceError {
11
+ }
12
+ type Fetch = typeof fetch;
13
+ /** `https://host[:port][/prefix]` without a trailing slash or userinfo. */
14
+ export declare function normaliseBase(raw: string): string;
15
+ /** Coolify: `Authorization: Bearer <token>`; a plain `read` token is enough. */
16
+ export declare function coolifySource(base: string, token: string, f?: Fetch): SourceGet;
17
+ /** Dokploy: `x-api-key`, tRPC procedures as `GET /api/<procedure>?<input>`. */
18
+ export declare function dokploySource(base: string, apiKey: string, f?: Fetch): SourceGet;
19
+ /**
20
+ * CapRover: sign in once (never retried: each wrong password starts a 30 s
21
+ * back-off), then send `x-captain-auth`. Errors arrive with HTTP 200 and a
22
+ * non-100 `status` in the envelope.
23
+ */
24
+ export declare function caproverSource(base: string, password: string, otp: string | undefined, f?: Fetch): Promise<SourceGet>;
25
+ export {};
26
+ //# sourceMappingURL=sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../../../src/lib/importers/sources.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,qBAAa,WAAY,SAAQ,KAAK;CAAG;AACzC,0DAA0D;AAC1D,qBAAa,gBAAiB,SAAQ,WAAW;CAAG;AAEpD,KAAK,KAAK,GAAG,OAAO,KAAK,CAAC;AAE1B,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASjD;AAgBD,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAE,KAAa,GAAG,SAAS,CAWtF;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAE,KAAa,GAAG,SAAS,CAUvF;AAID;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC,GAAE,KAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAqBlI"}