create-nifra 3.5.0 → 4.0.2

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 (106) hide show
  1. package/README.md +3 -3
  2. package/dist/agent-files.d.ts +41 -26
  3. package/dist/agent-files.d.ts.map +1 -1
  4. package/dist/agent-files.js +80 -47
  5. package/dist/agent-files.js.map +1 -1
  6. package/dist/agents.d.ts +3 -3
  7. package/dist/agents.d.ts.map +1 -1
  8. package/dist/agents.js +65 -69
  9. package/dist/agents.js.map +1 -1
  10. package/dist/auth.d.ts +5 -4
  11. package/dist/auth.d.ts.map +1 -1
  12. package/dist/auth.js +27 -14
  13. package/dist/auth.js.map +1 -1
  14. package/dist/cli.d.ts +23 -25
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +141 -130
  17. package/dist/cli.js.map +1 -1
  18. package/dist/db.d.ts.map +1 -1
  19. package/dist/db.js +49 -48
  20. package/dist/db.js.map +1 -1
  21. package/dist/scaffold/frameworks.d.ts +13 -38
  22. package/dist/scaffold/frameworks.d.ts.map +1 -1
  23. package/dist/scaffold/frameworks.js +9 -32
  24. package/dist/scaffold/frameworks.js.map +1 -1
  25. package/dist/scaffold/route-types.d.ts +9 -0
  26. package/dist/scaffold/route-types.d.ts.map +1 -0
  27. package/dist/scaffold/route-types.js +61 -0
  28. package/dist/scaffold/route-types.js.map +1 -0
  29. package/dist/scaffold/site-files.d.ts +14 -8
  30. package/dist/scaffold/site-files.d.ts.map +1 -1
  31. package/dist/scaffold/site-files.js +29 -60
  32. package/dist/scaffold/site-files.js.map +1 -1
  33. package/dist/scaffold/site.d.ts +8 -5
  34. package/dist/scaffold/site.d.ts.map +1 -1
  35. package/dist/scaffold/site.js +47 -34
  36. package/dist/scaffold/site.js.map +1 -1
  37. package/dist/scaffold/targets.d.ts +39 -0
  38. package/dist/scaffold/targets.d.ts.map +1 -0
  39. package/dist/scaffold/targets.js +116 -0
  40. package/dist/scaffold/targets.js.map +1 -0
  41. package/package.json +4 -1
  42. package/src/agent-files.ts +89 -47
  43. package/template/README.md +12 -6
  44. package/template/{src → backend}/app.test.ts +2 -2
  45. package/template/{src → backend}/app.ts +8 -3
  46. package/template/{src → backend}/index.ts +2 -2
  47. package/template/{src → backend}/routes.ts +1 -1
  48. package/template/nifra.assurance.ts +16 -14
  49. package/template/package.json +7 -7
  50. package/template/tsconfig.json +1 -1
  51. package/template-batteries/README.md +10 -6
  52. package/template-batteries/{src → backend}/app.test.ts +23 -23
  53. package/template-batteries/{src → backend}/app.ts +8 -3
  54. package/template-batteries/{src → backend}/index.ts +2 -2
  55. package/template-batteries/{src → backend}/notes.ts +1 -1
  56. package/template-batteries/nifra.assurance.ts +16 -14
  57. package/template-batteries/package.json +10 -9
  58. package/template-batteries/tsconfig.json +1 -1
  59. package/template-isr/README.md +3 -0
  60. package/template-isr/{backend.ts → backend/app.ts} +2 -0
  61. package/template-isr/{server.ts → backend/dev-server.ts} +4 -4
  62. package/template-isr/{worker.ts → backend/worker.ts} +4 -2
  63. package/template-isr/build.ts +3 -1
  64. package/template-isr/gitignore +7 -1
  65. package/template-isr/nifra.assurance.ts +15 -13
  66. package/template-isr/package.json +10 -9
  67. package/template-isr/routes/index.backend.ts +14 -0
  68. package/template-isr/routes/index.tsx +5 -17
  69. package/template-isr/tsconfig.json +5 -4
  70. package/template-isr/wrangler.toml +6 -1
  71. package/template-site/README.md +24 -23
  72. package/template-site/{backend.ts → backend/app.ts} +6 -4
  73. package/template-site/gitignore +5 -10
  74. package/template-site/nifra.assurance.ts +15 -13
  75. package/template-site/nifra.config.ts +4 -4
  76. package/template-site/routes/index.backend.ts +18 -0
  77. package/template-site/routes/index.tsx +2 -15
  78. package/template-site-preact/README.md +21 -20
  79. package/template-site-preact/nifra.config.ts +4 -4
  80. package/template-site-preact/routes/_layout.tsx +3 -1
  81. package/template-site-preact/routes/index.tsx +2 -15
  82. package/template-site-solid/README.md +21 -19
  83. package/template-site-solid/nifra.config.ts +5 -4
  84. package/template-site-solid/routes/index.tsx +2 -15
  85. package/template-site-svelte/README.md +21 -19
  86. package/template-site-svelte/nifra.config.ts +3 -2
  87. package/template-site-svelte/routes/index.svelte +3 -16
  88. package/template-site-vue/README.md +21 -20
  89. package/template-site-vue/nifra.config.ts +4 -3
  90. package/template-site-vue/routes/_layout.vue +21 -25
  91. package/template-site-vue/routes/index.vue +12 -18
  92. package/dist/scaffold/site-build.d.ts +0 -60
  93. package/dist/scaffold/site-build.d.ts.map +0 -1
  94. package/dist/scaffold/site-build.js +0 -198
  95. package/dist/scaffold/site-build.js.map +0 -1
  96. package/template-site/.dockerignore +0 -14
  97. package/template-site/Dockerfile +0 -25
  98. package/template-site/_worker.ts +0 -17
  99. package/template-site/deno.json +0 -7
  100. package/template-site/server-bun.ts +0 -35
  101. package/template-site/server-deno.ts +0 -38
  102. package/template-site/server-node.ts +0 -40
  103. package/template-site/server-vercel.ts +0 -17
  104. package/template-site/wrangler.toml +0 -4
  105. /package/template-isr/{page.ts → backend/page.ts} +0 -0
  106. /package/template-site/{counter.ts → backend/counter.ts} +0 -0
@@ -1,93 +1,60 @@
1
1
  /**
2
- * The rest of a site scaffold's mechanical files: the adapter re-export, the manifest, the tsconfig.
3
- *
4
- * Same argument as `site-build.ts`. These three were five copies each whose only real difference was
5
- * which framework they name, and keeping five copies is how `.vercel` came to be excluded from four
6
- * tsconfigs and not the fifth.
2
+ * A site scaffold's mechanical files: the adapter re-export, the manifest, the tsconfig. These were
3
+ * five copies each whose only real difference was which framework they name, and keeping five copies
4
+ * is how `.vercel` came to be excluded from four tsconfigs and not the fifth.
7
5
  */
8
6
  import { NIFRA_DEP_RANGE } from "./frameworks.js";
7
+ import { deployScript, TARGETS } from "./targets.js";
9
8
  /** JSON as these files are written: two-space indent, trailing newline. */
10
9
  const json = (value) => `${JSON.stringify(value, null, 2)}\n`;
11
10
  /**
12
- * `framework.ts` - the one file every server entry imports the adapter from, which is what keeps the
13
- * entries themselves framework-agnostic and therefore shareable.
11
+ * `backend/framework.ts` - the file the generated server entry imports the adapter from. It stays
12
+ * edge-bundlable: CLI-only tooling (Vite plugins, compilers) lives in `nifra.config.ts`.
14
13
  */
15
14
  export function renderFrameworkModule(framework) {
16
15
  return `// The frontend adapter for this app. \`create-nifra --framework <react|preact|vue|solid|svelte>\` swaps
17
- // this one line (and the routes + build config); every server entry imports the adapter from here, so
18
- // they stay framework-agnostic.
16
+ // this one line (and the routes + build config); the server entry \`nifra build\` generates imports the
17
+ // adapter from here, so it stays framework-agnostic.
19
18
  import { ${framework.adapter} } from "${framework.package}"
20
19
 
21
20
  export const adapter = ${framework.adapter}
22
21
  `;
23
22
  }
24
- /** The scripts every site scaffold ships, identical across frameworks. */
25
- const SCRIPTS = {
26
- dev: "nifra dev",
27
- preview: "bunx wrangler pages dev dist",
28
- build: "bun run build.ts",
29
- "build:bun": "bun run build-bun.ts",
30
- "build:node": "bun run build-node.ts",
31
- "build:deno": "bun run build-deno.ts",
32
- "build:vercel": "bun run build-vercel.ts",
33
- start: "bun dist-bun/server-bun.js",
34
- "start:node": "node dist-node/server-node.js",
35
- "deploy:cf": "wrangler pages deploy dist",
36
- "deploy:vercel": "vercel deploy --prebuilt",
37
- check: "nifra check && nifra assure",
38
- };
39
- /** Nifra packages every site depends on, whatever it renders with. */
40
- const NIFRA_RUNTIME = ["client", "core", "middleware", "schema", "deno", "node", "web"];
41
- export function renderPackageJson(framework) {
23
+ /** Nifra packages every site depends on, whatever it renders with and wherever it deploys. */
24
+ const NIFRA_RUNTIME = ["client", "core", "middleware", "schema", "web"];
25
+ export function renderPackageJson(framework, site) {
26
+ const spec = TARGETS[site.target];
42
27
  const dependencies = {};
43
- for (const name of NIFRA_RUNTIME)
28
+ for (const name of [...NIFRA_RUNTIME, ...(spec.runtime ?? [])].sort()) {
44
29
  dependencies[`@nifrajs/${name}`] = NIFRA_DEP_RANGE;
30
+ }
45
31
  dependencies[framework.package] = NIFRA_DEP_RANGE;
46
32
  Object.assign(dependencies, framework.runtimeDependencies);
33
+ const deploy = deployScript(site.target, site.name, site.docker);
47
34
  return json({
48
35
  name: "nifra-site",
49
36
  version: "0.0.0",
50
37
  type: "module",
51
38
  private: true,
52
- scripts: SCRIPTS,
39
+ scripts: {
40
+ dev: "nifra dev",
41
+ build: "nifra build",
42
+ ...(spec.start === undefined ? {} : { start: spec.start }),
43
+ ...(deploy === undefined ? {} : { deploy }),
44
+ check: "nifra check && nifra assure",
45
+ },
53
46
  dependencies,
54
47
  devDependencies: {
55
48
  "@nifrajs/cli": NIFRA_DEP_RANGE,
49
+ "@types/bun": "^1.4.2",
56
50
  ...framework.devDependencies,
57
51
  typescript: "^6.0.3",
58
52
  vite: "^8.2.1",
59
53
  },
60
54
  });
61
55
  }
62
- /**
63
- * Directories a build writes and a typecheck must not read, plus the entries that are run by Bun
64
- * rather than typechecked as part of the app.
65
- *
66
- * `.vercel` is in here for every framework. It was missing from React's copy alone, which is the shape
67
- * this whole refactor is about: `build-vercel.ts` writes there in all five, and four tsconfigs knew.
68
- */
69
- const EXCLUDE = [
70
- "node_modules",
71
- "dist",
72
- "dist-bun",
73
- "dist-node",
74
- "dist-deno",
75
- "dist-vercel",
76
- ".nifra",
77
- ".vercel",
78
- ".wrangler",
79
- "server-manifest.ts",
80
- "server-bun.ts",
81
- "server-node.ts",
82
- "server-deno.ts",
83
- "server-vercel.ts",
84
- "_worker.ts",
85
- "build.ts",
86
- "build-bun.ts",
87
- "build-node.ts",
88
- "build-deno.ts",
89
- "build-vercel.ts",
90
- ];
56
+ /** Directories a build writes and a typecheck must not read. */
57
+ const EXCLUDE = ["node_modules", "dist", ".nifra", ".nifra-build", ".vercel", ".wrangler"];
91
58
  export function renderTsconfig(framework) {
92
59
  const ts = framework.typescript;
93
60
  return json({
@@ -103,9 +70,11 @@ export function renderTsconfig(framework) {
103
70
  skipLibCheck: true,
104
71
  noEmit: true,
105
72
  verbatimModuleSyntax: true,
106
- ...(ts.types === undefined ? {} : { types: ts.types }),
73
+ types: ["bun", ...(ts.types ?? [])],
74
+ // Merges the generated `.nifra/types` tree in, so a route imports its types as `./+types/<name>`.
75
+ rootDirs: [".", "./.nifra/types"],
107
76
  },
108
- include: ts.includeTsx === false ? ["**/*.ts"] : ["**/*.ts", "**/*.tsx"],
77
+ include: ts.include ?? ["**/*.ts", "**/*.tsx"],
109
78
  exclude: EXCLUDE,
110
79
  });
111
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"site-files.js","sourceRoot":"","sources":["../../src/scaffold/site-files.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"site-files.js","sourceRoot":"","sources":["../../src/scaffold/site-files.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAsB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAqB,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEvE,2EAA2E;AAC3E,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AAE9E;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAwB;IAC5D,OAAO;;;WAGE,SAAS,CAAC,OAAO,YAAY,SAAS,CAAC,OAAO;;yBAEhC,SAAS,CAAC,OAAO;CACzC,CAAA;AACD,CAAC;AAED,8FAA8F;AAC9F,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;AAUvE,MAAM,UAAU,iBAAiB,CAAC,SAAwB,EAAE,IAAgB;IAC1E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACjC,MAAM,YAAY,GAA2B,EAAE,CAAA;IAC/C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACtE,YAAY,CAAC,YAAY,IAAI,EAAE,CAAC,GAAG,eAAe,CAAA;IACpD,CAAC;IACD,YAAY,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,eAAe,CAAA;IACjD,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,mBAAmB,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAEhE,OAAO,IAAI,CAAC;QACV,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,IAAI;QACb,OAAO,EAAE;YACP,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,aAAa;YACpB,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YAC1D,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;YAC3C,KAAK,EAAE,6BAA6B;SACrC;QACD,YAAY;QACZ,eAAe,EAAE;YACf,cAAc,EAAE,eAAe;YAC/B,YAAY,EAAE,QAAQ;YACtB,GAAG,SAAS,CAAC,eAAe;YAC5B,UAAU,EAAE,QAAQ;YACpB,IAAI,EAAE,QAAQ;SACf;KACF,CAAC,CAAA;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,OAAO,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;AAE1F,MAAM,UAAU,cAAc,CAAC,SAAwB;IACrD,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAA;IAC/B,OAAO,IAAI,CAAC;QACV,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC;YACtC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;YAChD,GAAG,CAAC,EAAE,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,eAAe,EAAE,CAAC;YACpF,MAAM,EAAE,IAAI;YACZ,wBAAwB,EAAE,IAAI;YAC9B,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,IAAI;YACZ,oBAAoB,EAAE,IAAI;YAC1B,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YACnC,kGAAkG;YAClG,QAAQ,EAAE,CAAC,GAAG,EAAE,gBAAgB,CAAC;SAClC;QACD,OAAO,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;QAC9C,OAAO,EAAE,OAAO;KACjB,CAAC,CAAA;AACJ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type FrameworkSpec } from "./frameworks.js";
2
+ import { type SiteTarget } from "./site-files.js";
2
3
  /**
3
4
  * Files identical in every site scaffold, taken from the base directory.
4
5
  *
@@ -9,16 +10,18 @@ import { type FrameworkSpec } from "./frameworks.js";
9
10
  export declare const SHARED_SITE_FILES: readonly string[];
10
11
  /** Files each framework supplies itself, relative to its overlay directory. */
11
12
  export declare const FRAMEWORK_SITE_FILES: readonly string[];
12
- /** Route files, whose extension is the framework's own. */
13
+ /** Route frontend files, whose extension is the framework's own. The backend half is shared. */
13
14
  export declare const ROUTE_BASENAMES: readonly string[];
14
15
  /** Extension the framework's route files carry. */
15
16
  export declare function routeExtension(framework: FrameworkSpec): string;
16
17
  /** The base directory: the shared files plus React's own, which is also the React overlay. */
17
18
  export declare const SITE_BASE_DIR: string;
18
19
  export declare function overlayDir(framework: FrameworkSpec): string;
19
- /** Every file a site scaffold emits, and the text it holds. Generated files only. */
20
- export declare function generatedSiteFiles(framework: FrameworkSpec): Map<string, string>;
21
- export interface MaterializeOptions {
20
+ /** Every file a site scaffold generates, and the text it holds. */
21
+ export declare function generatedSiteFiles(framework: FrameworkSpec, site: SiteTarget): Map<string, string>;
22
+ /** The framework's `nifra.config.ts`, declaring the target `nifra build` emits. */
23
+ export declare function withTarget(config: string, site: SiteTarget): string;
24
+ export interface MaterializeOptions extends SiteTarget {
22
25
  /** Overwrite an existing destination. Default false, which refuses rather than clobbers. */
23
26
  readonly force?: boolean;
24
27
  }
@@ -29,5 +32,5 @@ export interface MaterializeOptions {
29
32
  * `errorOnExist` did that before this was generated, and losing it would turn a mistyped path into
30
33
  * silent data loss in someone's working directory. `--force` is what `bun create nifra .` needs.
31
34
  */
32
- export declare function materializeSite(target: string, id: string, options?: MaterializeOptions): Promise<void>;
35
+ export declare function materializeSite(target: string, id: string, options: MaterializeOptions): Promise<void>;
33
36
  //# sourceMappingURL=site.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../../src/scaffold/site.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,iBAAiB,CAAA;AAInE;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAc9C,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAAqC,CAAA;AAEvF,2DAA2D;AAC3D,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAiC,CAAA;AAE9E,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAI/D;AAGD,8FAA8F;AAC9F,eAAO,MAAM,aAAa,QAA0C,CAAA;AACpE,wBAAgB,UAAU,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAI3D;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAOhF;AAED,MAAM,WAAW,kBAAkB;IACjC,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqBf"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../../src/scaffold/site.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,iBAAiB,CAAA;AAEnE,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAA;AAGxB;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAM9C,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAAqC,CAAA;AAEvF,gGAAgG;AAChG,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAAiC,CAAA;AAE9E,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAI/D;AAGD,8FAA8F;AAC9F,eAAO,MAAM,aAAa,QAA0C,CAAA;AACpE,wBAAgB,UAAU,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAI3D;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,UAAU,GACf,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQrB;AAcD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAEnE;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -1,21 +1,23 @@
1
1
  /**
2
- * Compose a site scaffold: shared base, generated files, framework overlay.
2
+ * Compose a site scaffold: shared base, generated files, framework overlay, target files.
3
3
  *
4
- * A site is 26 files. Thirteen are the same whatever you render with - the Dockerfile, every server
5
- * entry, the worker, the assurance config - eight are mechanical enough to emit from a model, and five
6
- * are genuinely the framework's own. Keeping five copies of all 26 is what let `.vercel` reach four
7
- * tsconfigs and not the fifth, and a Vercel comment reach one build entry and not the other four.
4
+ * A site is the same few files whatever it renders with or deploys to - the backend, the assurance
5
+ * config, the landing page's backend half - plus what is mechanical enough to emit from a model (the
6
+ * manifest, the tsconfig, the adapter module, the target's config), and the files that are genuinely
7
+ * the framework's own. There is no per-runtime server entry or build script: `nifra build` generates
8
+ * the target's entry from `backend/` and `routes/`.
8
9
  *
9
- * The five that stay literal stay literal on purpose. `nifra.config.ts` explains why Solid wants a
10
- * `solid` resolve condition and what `@preact/preset-vite` is; the routes are the app a user reads
11
- * first. That prose belongs in a file you can open, not in a TypeScript string.
10
+ * The framework files stay literal on purpose. `nifra.config.ts` explains why Solid wants a `solid`
11
+ * resolve condition and what `@preact/preset-vite` is; the routes are the app a user reads first. That
12
+ * prose belongs in a file you can open, not in a TypeScript string.
12
13
  */
13
- import { cp, mkdir, writeFile } from "node:fs/promises";
14
+ import { cp, mkdir, readFile, writeFile } from "node:fs/promises";
14
15
  import { dirname, join } from "node:path";
15
16
  import { fileURLToPath } from "node:url";
16
17
  import { frameworkSpec } from "./frameworks.js";
17
- import { BUILD_TARGETS, renderBuildFile } from "./site-build.js";
18
- import { renderFrameworkModule, renderPackageJson, renderTsconfig } from "./site-files.js";
18
+ import { starterRouteTypes } from "./route-types.js";
19
+ import { renderFrameworkModule, renderPackageJson, renderTsconfig, } from "./site-files.js";
20
+ import { targetFiles } from "./targets.js";
19
21
  /**
20
22
  * Files identical in every site scaffold, taken from the base directory.
21
23
  *
@@ -24,23 +26,15 @@ import { renderFrameworkModule, renderPackageJson, renderTsconfig } from "./site
24
26
  * here, and `site-composition.test.ts` fails if this list and the directory disagree.
25
27
  */
26
28
  export const SHARED_SITE_FILES = [
27
- ".dockerignore",
28
- "Dockerfile",
29
- "_worker.ts",
30
- "backend.ts",
31
- "counter.ts",
32
- "deno.json",
29
+ "backend/app.ts",
30
+ "backend/counter.ts",
33
31
  "gitignore",
34
32
  "nifra.assurance.ts",
35
- "server-bun.ts",
36
- "server-deno.ts",
37
- "server-node.ts",
38
- "server-vercel.ts",
39
- "wrangler.toml",
33
+ "routes/index.backend.ts",
40
34
  ];
41
35
  /** Files each framework supplies itself, relative to its overlay directory. */
42
36
  export const FRAMEWORK_SITE_FILES = ["README.md", "nifra.config.ts"];
43
- /** Route files, whose extension is the framework's own. */
37
+ /** Route frontend files, whose extension is the framework's own. The backend half is shared. */
44
38
  export const ROUTE_BASENAMES = ["_404", "_layout", "index"];
45
39
  /** Extension the framework's route files carry. */
46
40
  export function routeExtension(framework) {
@@ -58,16 +52,33 @@ export function overlayDir(framework) {
58
52
  ? SITE_BASE_DIR
59
53
  : join(here, "..", "..", `template-site-${framework.id}`);
60
54
  }
61
- /** Every file a site scaffold emits, and the text it holds. Generated files only. */
62
- export function generatedSiteFiles(framework) {
55
+ /** Every file a site scaffold generates, and the text it holds. */
56
+ export function generatedSiteFiles(framework, site) {
63
57
  const files = new Map();
64
- for (const target of BUILD_TARGETS)
65
- files.set(target.file, renderBuildFile(target, framework));
66
- files.set("framework.ts", renderFrameworkModule(framework));
67
- files.set("package.json", renderPackageJson(framework));
58
+ files.set("backend/framework.ts", renderFrameworkModule(framework));
59
+ files.set("package.json", renderPackageJson(framework, site));
68
60
  files.set("tsconfig.json", renderTsconfig(framework));
61
+ for (const [file, text] of targetFiles(site.target, site.name, site.docker))
62
+ files.set(file, text);
63
+ for (const [file, text] of starterRouteTypes(routeExtension(framework)))
64
+ files.set(file, text);
69
65
  return files;
70
66
  }
67
+ /**
68
+ * Declared for every target, not just the edge ones, so `nifra target cloudflare` later keeps the
69
+ * shared backend's rate limit working without a second edit.
70
+ */
71
+ const CLIENT_IP_DECLARATION = `// Cloudflare and Vercel expose no socket: the caller's address arrives in a header their edge
72
+ // overwrites (\`cf-connecting-ip\` / \`x-real-ip\`), and this trusts it so backend/app.ts's rate limit can
73
+ // tell visitors apart. Without it an edge build has no caller address and the limit refuses every
74
+ // request. It holds only while that edge is the one way in - served any other way (\`wrangler pages
75
+ // dev\`, your own workerd) the header is whatever the client sent. Bun, Node and Deno use the socket.
76
+ export const clientIp = "platform"
77
+ `;
78
+ /** The framework's `nifra.config.ts`, declaring the target `nifra build` emits. */
79
+ export function withTarget(config, site) {
80
+ return `${config.replace(/\n*$/, "\n")}\n${CLIENT_IP_DECLARATION}\n// The deploy target \`nifra build\` emits; \`nifra target <t>\` switches it.\nexport const target = "${site.target}"\n`;
81
+ }
71
82
  /**
72
83
  * Write a complete site scaffold into `target`.
73
84
  *
@@ -75,21 +86,23 @@ export function generatedSiteFiles(framework) {
75
86
  * `errorOnExist` did that before this was generated, and losing it would turn a mistyped path into
76
87
  * silent data loss in someone's working directory. `--force` is what `bun create nifra .` needs.
77
88
  */
78
- export async function materializeSite(target, id, options = {}) {
89
+ export async function materializeSite(target, id, options) {
79
90
  const framework = frameworkSpec(id);
80
91
  const overlay = overlayDir(framework);
81
92
  const force = options.force === true;
82
93
  const copy = (from, to) => cp(from, to, force ? { force: true } : { errorOnExist: true, force: false });
83
94
  // `wx` fails when the file exists, which is the write-side equivalent of `errorOnExist`.
84
95
  const emit = (to, contents) => writeFile(to, contents, force ? {} : { flag: "wx" });
85
- await mkdir(join(target, "routes"), { recursive: true });
96
+ for (const dir of ["routes", "backend"])
97
+ await mkdir(join(target, dir), { recursive: true });
86
98
  for (const file of SHARED_SITE_FILES)
87
99
  await copy(join(SITE_BASE_DIR, file), join(target, file));
88
- for (const [file, contents] of generatedSiteFiles(framework)) {
100
+ for (const [file, contents] of generatedSiteFiles(framework, options)) {
101
+ await mkdir(dirname(join(target, file)), { recursive: true });
89
102
  await emit(join(target, file), contents);
90
103
  }
91
- for (const file of FRAMEWORK_SITE_FILES)
92
- await copy(join(overlay, file), join(target, file));
104
+ await copy(join(overlay, "README.md"), join(target, "README.md"));
105
+ await emit(join(target, "nifra.config.ts"), withTarget(await readFile(join(overlay, "nifra.config.ts"), "utf8"), options));
93
106
  const extension = routeExtension(framework);
94
107
  for (const base of ROUTE_BASENAMES) {
95
108
  const name = join("routes", `${base}.${extension}`);
@@ -1 +1 @@
1
- {"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/scaffold/site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAsB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAE1F;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,eAAe;IACf,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,WAAW;IACX,oBAAoB;IACpB,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,kBAAkB;IAClB,eAAe;CAChB,CAAA;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAA;AAEvF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;AAE9E,mDAAmD;AACnD,MAAM,UAAU,cAAc,CAAC,SAAwB;IACrD,IAAI,SAAS,CAAC,EAAE,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC9C,IAAI,SAAS,CAAC,EAAE,KAAK,KAAK;QAAE,OAAO,KAAK,CAAA;IACxC,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACpD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAA;AACpE,MAAM,UAAU,UAAU,CAAC,SAAwB;IACjD,OAAO,SAAS,CAAC,EAAE,KAAK,OAAO;QAC7B,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,SAAS,CAAC,EAAE,EAAE,CAAC,CAAA;AAC7D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,SAAwB;IACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAA;IACvC,KAAK,MAAM,MAAM,IAAI,aAAa;QAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IAC9F,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAA;IAC3D,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAA;IACvD,KAAK,CAAC,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAA;IACrD,OAAO,KAAK,CAAA;AACd,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,EAAU,EACV,UAA8B,EAAE;IAEhC,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC,CAAA;IACnC,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,KAAK,IAAI,CAAA;IACpC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAU,EAAiB,EAAE,CACvD,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;IAC9E,yFAAyF;IACzF,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,QAAgB,EAAiB,EAAE,CAC3D,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAEtD,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACxD,KAAK,MAAM,IAAI,IAAI,iBAAiB;QAAE,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAC/F,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAA;IAC1C,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,oBAAoB;QAAE,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IAC5F,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;IAC3C,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,IAAI,SAAS,EAAE,CAAC,CAAA;QACnD,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IACrD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../../src/scaffold/site.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Where a site deploys. A scaffold picks ONE target (`--target`, default `bun`): `nifra build` generates
3
+ * that target's server entry from `backend/` and `routes/`, so the app carries no per-runtime entry or
4
+ * build script - only the target's own config file, when it has one, and the scripts that run it.
5
+ * `nifra target <t>` switches it later.
6
+ */
7
+ export declare const DEPLOY_TARGETS: readonly ["bun", "node", "deno", "cloudflare", "vercel"];
8
+ export type DeployTarget = (typeof DEPLOY_TARGETS)[number];
9
+ export interface TargetSpec {
10
+ readonly label: string;
11
+ /** `start` script: run the built app locally. */
12
+ readonly start?: string;
13
+ /** `deploy` script. Self-hosted targets have none unless the app is built into a Docker image. */
14
+ readonly deploy?: string;
15
+ /** `@nifrajs/*` packages the generated server entry imports beyond the shared set. */
16
+ readonly runtime?: readonly string[];
17
+ /** Whether `--docker` applies: a self-hosting server, not a platform's own runtime. */
18
+ readonly docker: boolean;
19
+ }
20
+ export declare const TARGETS: Readonly<Record<DeployTarget, TargetSpec>>;
21
+ export declare function isDeployTarget(value: string): value is DeployTarget;
22
+ /**
23
+ * The project name as a platform knows the app: a Docker image tag and a Cloudflare Pages or Deno Deploy
24
+ * project name take lowercase letters, digits, and "-", where the project itself may be `MyApp`,
25
+ * `my_app`, or `my.app`.
26
+ */
27
+ export declare function deployName(name: string): string;
28
+ /** The `deploy` script for `target`, or `undefined` when there is none. */
29
+ export declare function deployScript(target: DeployTarget, name: string, docker: boolean): string | undefined;
30
+ /** A Dockerfile that builds with Bun and runs the self-contained `dist/` on the target's runtime. */
31
+ export declare function renderDockerfile(target: "bun" | "node"): string;
32
+ export declare const DOCKERIGNORE = "node_modules\ndist\n.nifra\n.nifra-build\n.vercel\n.wrangler\n.git\n*.log\n";
33
+ /** `deno.json` for the Deno target: Bun builds, Deno runs and deploys the bundle. */
34
+ export declare const DENO_JSON: string;
35
+ /** `wrangler.toml` for the Cloudflare target; `NAME` is the Pages project. */
36
+ export declare const WRANGLER_TOML = "name = \"NAME\"\npages_build_output_dir = \"dist\"\n# 2025-04-01 or later: from that date `nodejs_compat` fills `process.env` from the project's variables,\n# where backend/app.ts reads NIFRA_ALLOW_MEMORY_RATE_LIMIT; until that variable is \"true\" the worker\n# refuses to start. Set it (a Pages variable, or a [vars] table here) only if a per-isolate rate limit\n# will do: Cloudflare runs many isolates and each counts alone. `bun run start` sets it for its one\n# local process.\ncompatibility_date = \"2025-04-01\"\ncompatibility_flags = [\"nodejs_compat\"]\n";
37
+ /** The config files `target` needs at the app root, by name. */
38
+ export declare function targetFiles(target: DeployTarget, name: string, docker: boolean): Map<string, string>;
39
+ //# sourceMappingURL=targets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/scaffold/targets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,cAAc,0DAA2D,CAAA;AACtF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAE1D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,kGAAkG;IAClG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,sFAAsF;IACtF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,uFAAuF;IACvF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAiB9D,CAAA;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,GACd,MAAM,GAAG,SAAS,CAKpB;AAQD,qGAAqG;AACrG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAwB/D;AAED,eAAO,MAAM,YAAY,gFAQxB,CAAA;AAED,qFAAqF;AACrF,eAAO,MAAM,SAAS,QAOjB,CAAA;AAEL,8EAA8E;AAC9E,eAAO,MAAM,aAAa,yjBASzB,CAAA;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,GACd,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAUrB"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Where a site deploys. A scaffold picks ONE target (`--target`, default `bun`): `nifra build` generates
3
+ * that target's server entry from `backend/` and `routes/`, so the app carries no per-runtime entry or
4
+ * build script - only the target's own config file, when it has one, and the scripts that run it.
5
+ * `nifra target <t>` switches it later.
6
+ */
7
+ export const DEPLOY_TARGETS = ["bun", "node", "deno", "cloudflare", "vercel"];
8
+ export const TARGETS = {
9
+ bun: { label: "Bun", start: "bun dist/server.js", docker: true },
10
+ node: { label: "Node", start: "node dist/server.js", runtime: ["node"], docker: true },
11
+ deno: {
12
+ label: "Deno Deploy",
13
+ start: "deno run --allow-net --allow-read --allow-env dist/server.js",
14
+ deploy: "deployctl deploy --prod --entrypoint=dist/server.js",
15
+ docker: false,
16
+ },
17
+ cloudflare: {
18
+ label: "Cloudflare Pages",
19
+ // `pages dev` is only ever one local process - the single instance the memory rate limit allows.
20
+ start: "wrangler pages dev dist --binding NIFRA_ALLOW_MEMORY_RATE_LIMIT=true",
21
+ deploy: "wrangler pages deploy dist",
22
+ docker: false,
23
+ },
24
+ vercel: { label: "Vercel", deploy: "vercel deploy --prebuilt", docker: false },
25
+ };
26
+ export function isDeployTarget(value) {
27
+ return DEPLOY_TARGETS.includes(value);
28
+ }
29
+ /**
30
+ * The project name as a platform knows the app: a Docker image tag and a Cloudflare Pages or Deno Deploy
31
+ * project name take lowercase letters, digits, and "-", where the project itself may be `MyApp`,
32
+ * `my_app`, or `my.app`.
33
+ */
34
+ export function deployName(name) {
35
+ return name
36
+ .toLowerCase()
37
+ .replace(/[^a-z0-9]+/g, "-")
38
+ .replace(/-+$/, "");
39
+ }
40
+ /** The `deploy` script for `target`, or `undefined` when there is none. */
41
+ export function deployScript(target, name, docker) {
42
+ const image = deployName(name);
43
+ return docker
44
+ ? `docker build -t ${image} . && docker run -p 3000:3000 ${image}`
45
+ : TARGETS[target].deploy;
46
+ }
47
+ /** The image a Docker scaffold runs the built server in. */
48
+ const DOCKER_RUN = {
49
+ bun: { image: "oven/bun:1-slim", user: "bun", cmd: '["bun", "dist/server.js"]' },
50
+ node: { image: "node:22-slim", user: "node", cmd: '["node", "dist/server.js"]' },
51
+ };
52
+ /** A Dockerfile that builds with Bun and runs the self-contained `dist/` on the target's runtime. */
53
+ export function renderDockerfile(target) {
54
+ const run = DOCKER_RUN[target];
55
+ return `# Build with Bun (nifra's build toolchain), then run the self-contained bundle - the final image
56
+ # carries no build tools or node_modules.
57
+ # docker build -t my-nifra-app .
58
+ # docker run -p 3000:3000 my-nifra-app
59
+ FROM oven/bun:1 AS build
60
+ WORKDIR /app
61
+ # Copy manifests first so the install layer caches across source-only changes.
62
+ COPY package.json bun.lock* ./
63
+ RUN bun install
64
+ COPY . .
65
+ RUN bun run build
66
+
67
+ FROM ${run.image} AS run
68
+ WORKDIR /app
69
+ ENV NODE_ENV=production
70
+ ENV PORT=3000
71
+ COPY --from=build /app/dist ./dist
72
+ # The bundle needs no elevated privileges; a compromised request handler should not inherit root.
73
+ USER ${run.user}
74
+ EXPOSE 3000
75
+ CMD ${run.cmd}
76
+ `;
77
+ }
78
+ export const DOCKERIGNORE = `node_modules
79
+ dist
80
+ .nifra
81
+ .nifra-build
82
+ .vercel
83
+ .wrangler
84
+ .git
85
+ *.log
86
+ `;
87
+ /** `deno.json` for the Deno target: Bun builds, Deno runs and deploys the bundle. */
88
+ export const DENO_JSON = `${JSON.stringify({
89
+ tasks: { start: TARGETS.deno.start },
90
+ "//": "Build with Bun (`bun run build`), run the self-contained bundle on Deno. Deploy: deployctl deploy --prod --entrypoint=dist/server.js",
91
+ }, null, 2)}\n`;
92
+ /** `wrangler.toml` for the Cloudflare target; `NAME` is the Pages project. */
93
+ export const WRANGLER_TOML = `name = "NAME"
94
+ pages_build_output_dir = "dist"
95
+ # 2025-04-01 or later: from that date \`nodejs_compat\` fills \`process.env\` from the project's variables,
96
+ # where backend/app.ts reads NIFRA_ALLOW_MEMORY_RATE_LIMIT; until that variable is "true" the worker
97
+ # refuses to start. Set it (a Pages variable, or a [vars] table here) only if a per-isolate rate limit
98
+ # will do: Cloudflare runs many isolates and each counts alone. \`bun run start\` sets it for its one
99
+ # local process.
100
+ compatibility_date = "2025-04-01"
101
+ compatibility_flags = ["nodejs_compat"]
102
+ `;
103
+ /** The config files `target` needs at the app root, by name. */
104
+ export function targetFiles(target, name, docker) {
105
+ const files = new Map();
106
+ if (target === "deno")
107
+ files.set("deno.json", DENO_JSON);
108
+ if (target === "cloudflare")
109
+ files.set("wrangler.toml", WRANGLER_TOML.replace("NAME", deployName(name)));
110
+ if (docker && (target === "bun" || target === "node")) {
111
+ files.set("Dockerfile", renderDockerfile(target));
112
+ files.set(".dockerignore", DOCKERIGNORE);
113
+ }
114
+ return files;
115
+ }
116
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/scaffold/targets.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nifra",
3
- "version": "3.5.0",
3
+ "version": "4.0.2",
4
4
  "description": "Scaffold a new nifra app - `bun create nifra <dir>`.",
5
5
  "keywords": [
6
6
  "bun",
@@ -17,6 +17,9 @@
17
17
  "cli"
18
18
  ],
19
19
  "type": "module",
20
+ "nifra": {
21
+ "environment": "backend"
22
+ },
20
23
  "bin": {
21
24
  "create-nifra": "./dist/cli.js"
22
25
  },