create-ragen-app 0.2.0 → 0.4.0

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 (39) hide show
  1. package/README.md +90 -7
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +218 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config-file.d.ts +14 -0
  6. package/dist/config-file.d.ts.map +1 -0
  7. package/dist/config-file.js +21 -0
  8. package/dist/config-file.js.map +1 -0
  9. package/dist/config-template.d.ts +30 -0
  10. package/dist/config-template.d.ts.map +1 -0
  11. package/dist/config-template.js +126 -0
  12. package/dist/config-template.js.map +1 -0
  13. package/dist/encryption-provider.d.ts +35 -0
  14. package/dist/encryption-provider.d.ts.map +1 -0
  15. package/dist/encryption-provider.js +63 -0
  16. package/dist/encryption-provider.js.map +1 -0
  17. package/dist/llm-provider.d.ts +17 -0
  18. package/dist/llm-provider.d.ts.map +1 -1
  19. package/dist/llm-provider.js +31 -1
  20. package/dist/llm-provider.js.map +1 -1
  21. package/dist/manifest.d.ts.map +1 -1
  22. package/dist/manifest.js +22 -4
  23. package/dist/manifest.js.map +1 -1
  24. package/dist/manual-setup.d.ts.map +1 -1
  25. package/dist/manual-setup.js +85 -16
  26. package/dist/manual-setup.js.map +1 -1
  27. package/dist/node-version.d.ts +54 -0
  28. package/dist/node-version.d.ts.map +1 -0
  29. package/dist/node-version.js +81 -0
  30. package/dist/node-version.js.map +1 -0
  31. package/dist/route-table.d.ts +31 -0
  32. package/dist/route-table.d.ts.map +1 -0
  33. package/dist/route-table.js +53 -0
  34. package/dist/route-table.js.map +1 -0
  35. package/dist/storage-provider.d.ts +49 -0
  36. package/dist/storage-provider.d.ts.map +1 -0
  37. package/dist/storage-provider.js +84 -0
  38. package/dist/storage-provider.js.map +1 -0
  39. package/package.json +2 -2
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Whether this Node can be used to create a Ragen installation.
3
+ *
4
+ * The distinction that matters: **the installation** needs Node 24, not this
5
+ * CLI. The CLI itself runs happily on older majors — it was published and
6
+ * verified on Node 22 by accident — so refusing on the grounds that "this
7
+ * tool requires Node 24" would be both untrue and unhelpfully broad.
8
+ *
9
+ * What genuinely breaks is the first-run setup the wizard performs on the
10
+ * caller's behalf: `npm install` across the monorepo, `prisma generate`,
11
+ * `migrate deploy` and the seed all run under whatever Node invoked the
12
+ * wizard. Getting a half-built `node_modules` out of that is the expensive
13
+ * failure, because it surfaces much later and nowhere near its cause. npm's
14
+ * own `EBADENGINE` warning does fire, but as one line inside a wall of
15
+ * install output, and it does not say what will break.
16
+ *
17
+ * So the check is gated on what the wizard is about to *do*:
18
+ *
19
+ * - running the setup steps → refuse, before anything is cloned
20
+ * - `--skip-install` → proceed, because nothing runs here; warn instead,
21
+ * since the scaffolded app still needs Node 24 to start
22
+ *
23
+ * `--yes` deliberately does not bypass it. That flag means "accept the
24
+ * defaults", not "ignore a requirement".
25
+ */
26
+ /**
27
+ * Kept in step with this package's `engines.node` by
28
+ * `src/__tests__/node-version.test.ts`, and with the repository's own Node
29
+ * version documented in AGENTS.md ("Node.js 24.x (Active LTS)").
30
+ */
31
+ export declare const REQUIRED_NODE_MAJOR = 24;
32
+ export type NodeVersionVerdict = {
33
+ kind: 'ok';
34
+ } | {
35
+ kind: 'warn';
36
+ message: string;
37
+ } | {
38
+ kind: 'refuse';
39
+ message: string;
40
+ };
41
+ export interface NodeVersionCheck {
42
+ /** As `process.version` gives it, e.g. `v22.22.3`. */
43
+ version: string;
44
+ /** False when `--skip-install` means the wizard runs nothing itself. */
45
+ willRunSetup: boolean;
46
+ }
47
+ /**
48
+ * Returns undefined for anything that is not a recognisable Node version, so
49
+ * an unexpected format cannot be read as "too old" and block an install that
50
+ * would have worked.
51
+ */
52
+ export declare function parseNodeMajor(version: string): number | undefined;
53
+ export declare function checkNodeVersion({ version, willRunSetup, }: NodeVersionCheck): NodeVersionVerdict;
54
+ //# sourceMappingURL=node-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-version.d.ts","sourceRoot":"","sources":["../src/node-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMlE;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,YAAY,GACb,EAAE,gBAAgB,GAAG,kBAAkB,CAkCvC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * Whether this Node can be used to create a Ragen installation.
4
+ *
5
+ * The distinction that matters: **the installation** needs Node 24, not this
6
+ * CLI. The CLI itself runs happily on older majors — it was published and
7
+ * verified on Node 22 by accident — so refusing on the grounds that "this
8
+ * tool requires Node 24" would be both untrue and unhelpfully broad.
9
+ *
10
+ * What genuinely breaks is the first-run setup the wizard performs on the
11
+ * caller's behalf: `npm install` across the monorepo, `prisma generate`,
12
+ * `migrate deploy` and the seed all run under whatever Node invoked the
13
+ * wizard. Getting a half-built `node_modules` out of that is the expensive
14
+ * failure, because it surfaces much later and nowhere near its cause. npm's
15
+ * own `EBADENGINE` warning does fire, but as one line inside a wall of
16
+ * install output, and it does not say what will break.
17
+ *
18
+ * So the check is gated on what the wizard is about to *do*:
19
+ *
20
+ * - running the setup steps → refuse, before anything is cloned
21
+ * - `--skip-install` → proceed, because nothing runs here; warn instead,
22
+ * since the scaffolded app still needs Node 24 to start
23
+ *
24
+ * `--yes` deliberately does not bypass it. That flag means "accept the
25
+ * defaults", not "ignore a requirement".
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.REQUIRED_NODE_MAJOR = void 0;
29
+ exports.parseNodeMajor = parseNodeMajor;
30
+ exports.checkNodeVersion = checkNodeVersion;
31
+ /**
32
+ * Kept in step with this package's `engines.node` by
33
+ * `src/__tests__/node-version.test.ts`, and with the repository's own Node
34
+ * version documented in AGENTS.md ("Node.js 24.x (Active LTS)").
35
+ */
36
+ exports.REQUIRED_NODE_MAJOR = 24;
37
+ /**
38
+ * Returns undefined for anything that is not a recognisable Node version, so
39
+ * an unexpected format cannot be read as "too old" and block an install that
40
+ * would have worked.
41
+ */
42
+ function parseNodeMajor(version) {
43
+ const match = /^v?(\d+)\./.exec(version.trim());
44
+ if (!match) {
45
+ return undefined;
46
+ }
47
+ return Number(match[1]);
48
+ }
49
+ function checkNodeVersion({ version, willRunSetup, }) {
50
+ const major = parseNodeMajor(version);
51
+ if (major === undefined || major >= exports.REQUIRED_NODE_MAJOR) {
52
+ return { kind: 'ok' };
53
+ }
54
+ if (!willRunSetup) {
55
+ return {
56
+ kind: 'warn',
57
+ message: [
58
+ `You are on Node ${major}, and a Ragen installation needs Node ${exports.REQUIRED_NODE_MAJOR}.`,
59
+ 'Nothing is being installed here, so the files will be written anyway —',
60
+ 'but switch before running npm install or the app in the new directory.',
61
+ ].join(' '),
62
+ };
63
+ }
64
+ return {
65
+ kind: 'refuse',
66
+ message: [
67
+ `A Ragen installation needs Node ${exports.REQUIRED_NODE_MAJOR}, and this is Node ${major}.`,
68
+ '',
69
+ 'Stopping before anything is written: the setup this runs for you —',
70
+ 'npm install, prisma generate, migrate and seed — would run under this',
71
+ 'Node and leave a tree that fails later, somewhere that does not point',
72
+ 'back here.',
73
+ '',
74
+ ` nvm use ${exports.REQUIRED_NODE_MAJOR} # or fnm, volta, asdf, …`,
75
+ '',
76
+ 'Or pass --skip-install to write the files now and run the setup',
77
+ 'yourself on a supported Node.',
78
+ ].join('\n'),
79
+ };
80
+ }
81
+ //# sourceMappingURL=node-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-version.js","sourceRoot":"","sources":["../src/node-version.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AA0BH,wCAMC;AAED,4CAqCC;AArED;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,EAAE,CAAC;AActC;;;;GAIG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,SAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,YAAY,GACK;IACjB,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAEtC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,2BAAmB,EAAE,CAAC;QACxD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE;gBACP,mBAAmB,KAAK,yCAAyC,2BAAmB,GAAG;gBACvF,wEAAwE;gBACxE,wEAAwE;aACzE,CAAC,IAAI,CAAC,GAAG,CAAC;SACZ,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,mCAAmC,2BAAmB,sBAAsB,KAAK,GAAG;YACpF,EAAE;YACF,oEAAoE;YACpE,uEAAuE;YACvE,uEAAuE;YACvE,YAAY;YACZ,EAAE;YACF,aAAa,2BAAmB,6BAA6B;YAC7D,EAAE;YACF,iEAAiE;YACjE,+BAA+B;SAChC,CAAC,IAAI,CAAC,IAAI,CAAC;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ /** Where every app finds the table: `defaultRouteTablePath()` walks up to it. */
2
+ export declare const ROUTE_TABLE_PATH = "infra/llm-gateway/routes.yaml";
3
+ export interface RouteTableEntry {
4
+ /** The id the application asks for — `DEFAULT_MODEL`, `EMBEDDINGS_MODEL`. */
5
+ modelName: string;
6
+ /** A `@ragenai/llm-gateway` provider id. */
7
+ provider: string;
8
+ /** The upstream's own name for the model, which may differ from the id. */
9
+ model: string;
10
+ }
11
+ /**
12
+ * The route table for a scaffolded installation.
13
+ *
14
+ * Written **over** the table shipped in the repository rather than beside it,
15
+ * which is the same thing this wizard already does to
16
+ * `infra/litellm/config.yaml`. Two reasons, and the second is the one that
17
+ * decides it:
18
+ *
19
+ * - The shipped table names Azure, Bedrock, Vertex and Scaleway. A new
20
+ * installation has credentials for none of them, so every entry in it is a
21
+ * route to a 401.
22
+ * - `LLM_ROUTES_PATH` would be the alternative, and a *relative* one is a
23
+ * trap: `routeTableFromEnv` joins it to `process.cwd()`, which is a
24
+ * different directory for `apps/web`, `apps/api` and `apps/worker`. An
25
+ * absolute path avoids that and then breaks the moment the directory is
26
+ * moved. Writing the file where the default lookup already walks to it
27
+ * needs no variable at all.
28
+ */
29
+ export declare function renderRouteTable(entries: readonly RouteTableEntry[]): string;
30
+ export declare function writeRouteTable(targetDir: string, entries: readonly RouteTableEntry[]): void;
31
+ //# sourceMappingURL=route-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-table.d.ts","sourceRoot":"","sources":["../src/route-table.ts"],"names":[],"mappings":"AAGA,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,kCAAkC,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,CAyB5E;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,IAAI,CAEN"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROUTE_TABLE_PATH = void 0;
4
+ exports.renderRouteTable = renderRouteTable;
5
+ exports.writeRouteTable = writeRouteTable;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ /** Where every app finds the table: `defaultRouteTablePath()` walks up to it. */
9
+ exports.ROUTE_TABLE_PATH = 'infra/llm-gateway/routes.yaml';
10
+ /**
11
+ * The route table for a scaffolded installation.
12
+ *
13
+ * Written **over** the table shipped in the repository rather than beside it,
14
+ * which is the same thing this wizard already does to
15
+ * `infra/litellm/config.yaml`. Two reasons, and the second is the one that
16
+ * decides it:
17
+ *
18
+ * - The shipped table names Azure, Bedrock, Vertex and Scaleway. A new
19
+ * installation has credentials for none of them, so every entry in it is a
20
+ * route to a 401.
21
+ * - `LLM_ROUTES_PATH` would be the alternative, and a *relative* one is a
22
+ * trap: `routeTableFromEnv` joins it to `process.cwd()`, which is a
23
+ * different directory for `apps/web`, `apps/api` and `apps/worker`. An
24
+ * absolute path avoids that and then breaks the moment the directory is
25
+ * moved. Writing the file where the default lookup already walks to it
26
+ * needs no variable at all.
27
+ */
28
+ function renderRouteTable(entries) {
29
+ const routes = entries
30
+ .map(({ modelName, provider, model }) => ` ${modelName}:\n provider: ${provider}\n model: ${model}\n`)
31
+ .join('');
32
+ return `# Written by create-ragen-app for this installation.
33
+ #
34
+ # Which upstream serves each model id the application asks for. Ragen calls
35
+ # these providers itself — LLM_GATEWAY=native — with no proxy in the path.
36
+ #
37
+ # This replaced the table shipped in the repository, which routes to Azure,
38
+ # Bedrock, Vertex and Scaleway. Those entries are not wrong, they are simply
39
+ # not yours: nothing here has credentials for them.
40
+ #
41
+ # To serve another model, add an entry. The key is the id the application asks
42
+ # for (DEFAULT_MODEL, EMBEDDINGS_MODEL, REPHRASE_MODEL); \`model\` is the
43
+ # upstream's own name for it, which is not always the same string. Credentials
44
+ # stay in the environment and never appear here.
45
+ version: 1
46
+
47
+ routes:
48
+ ${routes}`;
49
+ }
50
+ function writeRouteTable(targetDir, entries) {
51
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(targetDir, exports.ROUTE_TABLE_PATH), renderRouteTable(entries));
52
+ }
53
+ //# sourceMappingURL=route-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-table.js","sourceRoot":"","sources":["../src/route-table.ts"],"names":[],"mappings":";;;AAiCA,4CAyBC;AAED,0CAKC;AAjED,qCAAwC;AACxC,yCAAiC;AAEjC,iFAAiF;AACpE,QAAA,gBAAgB,GAAG,+BAA+B,CAAC;AAWhE;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,gBAAgB,CAAC,OAAmC;IAClE,MAAM,MAAM,GAAG,OAAO;SACnB,GAAG,CACF,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,CACjC,KAAK,SAAS,oBAAoB,QAAQ,gBAAgB,KAAK,IAAI,CACtE;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO;;;;;;;;;;;;;;;;EAgBP,MAAM,EAAE,CAAC;AACX,CAAC;AAED,SAAgB,eAAe,CAC7B,SAAiB,EACjB,OAAmC;IAEnC,IAAA,uBAAa,EAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,wBAAgB,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Where uploaded documents live.
3
+ *
4
+ * The wizard skipped this until now and sent people to a manual guide, which
5
+ * is the one question where getting it wrong is expensive: `STORAGE_PROVIDER=s3`
6
+ * with a missing credential does not fail at boot in every app, it fails at
7
+ * the first upload, as a storage error three layers from the cause.
8
+ *
9
+ * The variable names and the config field names below mirror `STORAGE_SEAM` in
10
+ * `@ragenai/env`. They are copied rather than imported because this package is
11
+ * published to npm and `@ragenai/env` is private, so a dependency on it would
12
+ * make `npm create ragen-app` unresolvable. The copy is held to the original
13
+ * by `tests/architecture/create-ragen-app-knows-the-provider-seams.test.ts` —
14
+ * the same arrangement `manifest.ts` already has with the `.env.example`
15
+ * files.
16
+ */
17
+ /**
18
+ * One field of a written config, and the variable it resolves from.
19
+ *
20
+ * `required` decides how the installer renders it: a required field is typed
21
+ * `string`, so it needs a fallback to compile, while an optional one takes
22
+ * `process.env.X` as it comes. Carrying it here rather than inferring from the
23
+ * name keeps the renderer from having a fourth opinion about which variables a
24
+ * provider needs.
25
+ */
26
+ export interface ConfigField {
27
+ field: string;
28
+ envVar: string;
29
+ required: boolean;
30
+ }
31
+ export type StorageChoice = 'local' | 's3';
32
+ export interface S3Answers {
33
+ bucket: string;
34
+ region: string;
35
+ accessKeyId: string;
36
+ secretAccessKey: string;
37
+ /** Blank selects AWS. Set for R2, Scaleway, MinIO or Ceph. */
38
+ endpoint: string;
39
+ }
40
+ export interface StorageSelection {
41
+ provider: StorageChoice;
42
+ /** Written to the root `.env.local` — credentials never go in the config. */
43
+ envUpdates: Record<string, string>;
44
+ /** The config fields, already named as the config names them. */
45
+ configFields: ConfigField[];
46
+ }
47
+ export declare const STORAGE_LABELS: Record<StorageChoice, string>;
48
+ export declare function resolveStorageSelection(provider: StorageChoice, answers?: S3Answers): StorageSelection;
49
+ //# sourceMappingURL=storage-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-provider.d.ts","sourceRoot":"","sources":["../src/storage-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,IAAI,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,CAAC;IACxB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,iEAAiE;IACjE,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAGxD,CAAC;AAkBF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE,SAAS,GAClB,gBAAgB,CAmDlB"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ /**
3
+ * Where uploaded documents live.
4
+ *
5
+ * The wizard skipped this until now and sent people to a manual guide, which
6
+ * is the one question where getting it wrong is expensive: `STORAGE_PROVIDER=s3`
7
+ * with a missing credential does not fail at boot in every app, it fails at
8
+ * the first upload, as a storage error three layers from the cause.
9
+ *
10
+ * The variable names and the config field names below mirror `STORAGE_SEAM` in
11
+ * `@ragenai/env`. They are copied rather than imported because this package is
12
+ * published to npm and `@ragenai/env` is private, so a dependency on it would
13
+ * make `npm create ragen-app` unresolvable. The copy is held to the original
14
+ * by `tests/architecture/create-ragen-app-knows-the-provider-seams.test.ts` —
15
+ * the same arrangement `manifest.ts` already has with the `.env.example`
16
+ * files.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.STORAGE_LABELS = void 0;
20
+ exports.resolveStorageSelection = resolveStorageSelection;
21
+ exports.STORAGE_LABELS = {
22
+ local: 'Local filesystem (default — no cloud account needed)',
23
+ s3: 'S3-compatible (AWS, Cloudflare R2, Scaleway, MinIO, Ceph)',
24
+ };
25
+ /**
26
+ * A path-style endpoint is what Scaleway (dotted bucket names) and MinIO/Ceph
27
+ * need. Guessing it from the endpoint rather than asking keeps the wizard to
28
+ * one question per thing a person actually knows about their own storage.
29
+ */
30
+ function needsPathStyle(endpoint) {
31
+ const host = endpoint.trim().toLowerCase();
32
+ if (!host) {
33
+ return false;
34
+ }
35
+ return (!host.includes('amazonaws.com') &&
36
+ !host.includes('r2.cloudflarestorage.com'));
37
+ }
38
+ function resolveStorageSelection(provider, answers) {
39
+ if (provider === 'local' || !answers) {
40
+ return {
41
+ provider: 'local',
42
+ envUpdates: { STORAGE_PROVIDER: 'local' },
43
+ configFields: [
44
+ { field: 'path', envVar: 'STORAGE_LOCAL_PATH', required: false },
45
+ ],
46
+ };
47
+ }
48
+ const endpoint = answers.endpoint.trim();
49
+ const envUpdates = {
50
+ STORAGE_PROVIDER: 's3',
51
+ S3_BUCKET_NAME: answers.bucket.trim(),
52
+ S3_REGION: answers.region.trim(),
53
+ S3_ACCESS_KEY_ID: answers.accessKeyId.trim(),
54
+ S3_SECRET_ACCESS_KEY: answers.secretAccessKey.trim(),
55
+ };
56
+ const configFields = [
57
+ { field: 'bucketName', envVar: 'S3_BUCKET_NAME', required: true },
58
+ { field: 'region', envVar: 'S3_REGION', required: true },
59
+ { field: 'accessKeyId', envVar: 'S3_ACCESS_KEY_ID', required: true },
60
+ {
61
+ field: 'secretAccessKey',
62
+ envVar: 'S3_SECRET_ACCESS_KEY',
63
+ required: true,
64
+ },
65
+ ];
66
+ if (endpoint) {
67
+ envUpdates.S3_ENDPOINT_URL = endpoint;
68
+ configFields.push({
69
+ field: 'endpoint',
70
+ envVar: 'S3_ENDPOINT_URL',
71
+ required: false,
72
+ });
73
+ if (needsPathStyle(endpoint)) {
74
+ envUpdates.S3_FORCE_PATH_STYLE = 'true';
75
+ configFields.push({
76
+ field: 'forcePathStyle',
77
+ envVar: 'S3_FORCE_PATH_STYLE',
78
+ required: false,
79
+ });
80
+ }
81
+ }
82
+ return { provider: 's3', envUpdates, configFields };
83
+ }
84
+ //# sourceMappingURL=storage-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-provider.js","sourceRoot":"","sources":["../src/storage-provider.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAyDH,0DAsDC;AA3EY,QAAA,cAAc,GAAkC;IAC3D,KAAK,EAAE,sDAAsD;IAC7D,EAAE,EAAE,2DAA2D;CAChE,CAAC;AAEF;;;;GAIG;AACH,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CACL,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC/B,CAAC,IAAI,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAC3C,CAAC;AACJ,CAAC;AAED,SAAgB,uBAAuB,CACrC,QAAuB,EACvB,OAAmB;IAEnB,IAAI,QAAQ,KAAK,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACrC,OAAO;YACL,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,EAAE,gBAAgB,EAAE,OAAO,EAAE;YACzC,YAAY,EAAE;gBACZ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE,QAAQ,EAAE,KAAK,EAAE;aACjE;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEzC,MAAM,UAAU,GAA2B;QACzC,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE;QACrC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE;QAChC,gBAAgB,EAAE,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE;QAC5C,oBAAoB,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE;KACrD,CAAC;IAEF,MAAM,YAAY,GAAkB;QAClC,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE;QACjE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE;QACxD,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,IAAI,EAAE;QACpE;YACE,KAAK,EAAE,iBAAiB;YACxB,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE,IAAI;SACf;KACF,CAAC;IAEF,IAAI,QAAQ,EAAE,CAAC;QACb,UAAU,CAAC,eAAe,GAAG,QAAQ,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC;YAChB,KAAK,EAAE,UAAU;YACjB,MAAM,EAAE,iBAAiB;YACzB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QAEH,IAAI,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,UAAU,CAAC,mBAAmB,GAAG,MAAM,CAAC;YACxC,YAAY,CAAC,IAAI,CAAC;gBAChB,KAAK,EAAE,gBAAgB;gBACvB,MAAM,EAAE,qBAAqB;gBAC7B,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AACtD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ragen-app",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "Scaffold a self-hosted Ragen AI installation with one command",
6
6
  "license": "Apache-2.0",
@@ -22,7 +22,7 @@
22
22
  "scripts": {
23
23
  "build": "tsc -p tsconfig.json",
24
24
  "clean": "rm -rf dist",
25
- "prepare": "npm run clean && npm run build",
25
+ "prepack": "npm run clean && npm run build",
26
26
  "lint": "eslint",
27
27
  "typecheck": "tsc --noEmit --incremental --tsBuildInfoFile ./typecheck.tsbuildinfo"
28
28
  },