@cmj/juice 0.0.1

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 (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/dist/cli/commands.d.ts +29 -0
  4. package/dist/cli/commands.d.ts.map +1 -0
  5. package/dist/cli/commands.js +102 -0
  6. package/dist/cli/commands.js.map +1 -0
  7. package/dist/cli/create.d.ts +35 -0
  8. package/dist/cli/create.d.ts.map +1 -0
  9. package/dist/cli/create.js +108 -0
  10. package/dist/cli/create.js.map +1 -0
  11. package/dist/cli/index.d.ts +3 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +97 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/templates.d.ts +14 -0
  16. package/dist/cli/templates.d.ts.map +1 -0
  17. package/dist/cli/templates.js +154 -0
  18. package/dist/cli/templates.js.map +1 -0
  19. package/dist/compiler/errors.d.ts +91 -0
  20. package/dist/compiler/errors.d.ts.map +1 -0
  21. package/dist/compiler/errors.js +110 -0
  22. package/dist/compiler/errors.js.map +1 -0
  23. package/dist/compiler/manifest.d.ts +39 -0
  24. package/dist/compiler/manifest.d.ts.map +1 -0
  25. package/dist/compiler/manifest.js +78 -0
  26. package/dist/compiler/manifest.js.map +1 -0
  27. package/dist/compiler/parse.d.ts +126 -0
  28. package/dist/compiler/parse.d.ts.map +1 -0
  29. package/dist/compiler/parse.js +246 -0
  30. package/dist/compiler/parse.js.map +1 -0
  31. package/dist/compiler/plugin.d.ts +43 -0
  32. package/dist/compiler/plugin.d.ts.map +1 -0
  33. package/dist/compiler/plugin.js +281 -0
  34. package/dist/compiler/plugin.js.map +1 -0
  35. package/dist/compiler/proxy.d.ts +42 -0
  36. package/dist/compiler/proxy.d.ts.map +1 -0
  37. package/dist/compiler/proxy.js +80 -0
  38. package/dist/compiler/proxy.js.map +1 -0
  39. package/dist/compiler/registry.d.ts +58 -0
  40. package/dist/compiler/registry.d.ts.map +1 -0
  41. package/dist/compiler/registry.js +79 -0
  42. package/dist/compiler/registry.js.map +1 -0
  43. package/dist/compiler/server-action-registry.d.ts +57 -0
  44. package/dist/compiler/server-action-registry.d.ts.map +1 -0
  45. package/dist/compiler/server-action-registry.js +76 -0
  46. package/dist/compiler/server-action-registry.js.map +1 -0
  47. package/dist/compiler/server-actions.d.ts +49 -0
  48. package/dist/compiler/server-actions.d.ts.map +1 -0
  49. package/dist/compiler/server-actions.js +89 -0
  50. package/dist/compiler/server-actions.js.map +1 -0
  51. package/dist/compiler/types.d.ts +188 -0
  52. package/dist/compiler/types.d.ts.map +1 -0
  53. package/dist/compiler/types.js +9 -0
  54. package/dist/compiler/types.js.map +1 -0
  55. package/dist/runtime/actions.d.ts +37 -0
  56. package/dist/runtime/actions.d.ts.map +1 -0
  57. package/dist/runtime/actions.js +167 -0
  58. package/dist/runtime/actions.js.map +1 -0
  59. package/dist/runtime/dev.d.ts +43 -0
  60. package/dist/runtime/dev.d.ts.map +1 -0
  61. package/dist/runtime/dev.js +260 -0
  62. package/dist/runtime/dev.js.map +1 -0
  63. package/dist/runtime/errors.d.ts +98 -0
  64. package/dist/runtime/errors.d.ts.map +1 -0
  65. package/dist/runtime/errors.js +124 -0
  66. package/dist/runtime/errors.js.map +1 -0
  67. package/dist/runtime/index.d.ts +3 -0
  68. package/dist/runtime/index.d.ts.map +1 -0
  69. package/dist/runtime/index.js +5 -0
  70. package/dist/runtime/index.js.map +1 -0
  71. package/dist/runtime/matcher.d.ts +44 -0
  72. package/dist/runtime/matcher.d.ts.map +1 -0
  73. package/dist/runtime/matcher.js +83 -0
  74. package/dist/runtime/matcher.js.map +1 -0
  75. package/dist/runtime/render.d.ts +25 -0
  76. package/dist/runtime/render.d.ts.map +1 -0
  77. package/dist/runtime/render.js +141 -0
  78. package/dist/runtime/render.js.map +1 -0
  79. package/dist/runtime/resolve.d.ts +24 -0
  80. package/dist/runtime/resolve.d.ts.map +1 -0
  81. package/dist/runtime/resolve.js +41 -0
  82. package/dist/runtime/resolve.js.map +1 -0
  83. package/dist/runtime/router.d.ts +74 -0
  84. package/dist/runtime/router.d.ts.map +1 -0
  85. package/dist/runtime/router.js +367 -0
  86. package/dist/runtime/router.js.map +1 -0
  87. package/dist/runtime/types.d.ts +245 -0
  88. package/dist/runtime/types.d.ts.map +1 -0
  89. package/dist/runtime/types.js +5 -0
  90. package/dist/runtime/types.js.map +1 -0
  91. package/package.json +92 -0
@@ -0,0 +1,154 @@
1
+ // ─────────────────────────────────────────────────────────────────
2
+ // @cmj/juice — CLI Template Files
3
+ // Pure functions that return file content strings for scaffolding.
4
+ // ─────────────────────────────────────────────────────────────────
5
+ export const DEPLOY_TARGETS = ['bun', 'node', 'cloudflare', 'deno'];
6
+ export const TARGET_LABELS = {
7
+ bun: 'Bun',
8
+ node: 'Node.js',
9
+ cloudflare: 'Cloudflare Workers',
10
+ deno: 'Deno',
11
+ };
12
+ export function packageJson({ name, target }) {
13
+ const startScript = {
14
+ bun: 'bun server.ts',
15
+ node: 'node dist/server.js',
16
+ cloudflare: 'wrangler dev',
17
+ deno: 'deno run --allow-net --allow-read server.ts',
18
+ };
19
+ const pkg = {
20
+ name,
21
+ private: true,
22
+ type: 'module',
23
+ scripts: {
24
+ dev: 'vite dev',
25
+ build: 'vite build',
26
+ start: startScript[target],
27
+ typecheck: 'tsc --noEmit',
28
+ },
29
+ dependencies: {
30
+ '@cmj/juice': '^0.0.1',
31
+ react: '^19.0.0',
32
+ 'react-dom': '^19.0.0',
33
+ },
34
+ devDependencies: {
35
+ '@types/react': '^19.0.0',
36
+ '@types/react-dom': '^19.0.0',
37
+ typescript: '^5.7.0',
38
+ vite: '^6.0.0',
39
+ },
40
+ };
41
+ // Bun and Deno have built-in types; Node needs @types/node
42
+ if (target === 'node') {
43
+ pkg.devDependencies['@types/node'] = '^22.0.0';
44
+ }
45
+ return JSON.stringify(pkg, null, 2) + '\n';
46
+ }
47
+ export function tsconfig() {
48
+ const config = {
49
+ compilerOptions: {
50
+ target: 'ES2022',
51
+ module: 'ESNext',
52
+ moduleResolution: 'bundler',
53
+ jsx: 'react-jsx',
54
+ strict: true,
55
+ noEmit: true,
56
+ esModuleInterop: true,
57
+ skipLibCheck: true,
58
+ isolatedModules: true,
59
+ verbatimModuleSyntax: true,
60
+ },
61
+ include: ['**/*.ts', '**/*.tsx'],
62
+ };
63
+ return JSON.stringify(config, null, 2) + '\n';
64
+ }
65
+ export function viteConfig() {
66
+ return `import { defineConfig } from 'vite';
67
+ import juice from '@cmj/juice/plugin';
68
+
69
+ export default defineConfig({
70
+ plugins: [juice()],
71
+ });
72
+ `;
73
+ }
74
+ // ── Server entry per target ─────────────────────────────────────
75
+ const SERVER_PREAMBLE = `import { createRouter } from '@cmj/juice/runtime';
76
+ import type { FlightManifest } from '@cmj/juice/runtime';
77
+
78
+ const manifest: FlightManifest = {
79
+ routes: {
80
+ '/': { moduleId: './app/routes/home.tsx' },
81
+ },
82
+ clientModules: {},
83
+ serverActions: {},
84
+ };
85
+
86
+ const handler = createRouter(manifest, {
87
+ root: import.meta.url,
88
+ });
89
+ `;
90
+ const SERVER_ADAPTERS = {
91
+ bun: `
92
+ Bun.serve({
93
+ port: 3000,
94
+ fetch: handler,
95
+ });
96
+
97
+ console.log('🧃 Listening on http://localhost:3000');
98
+ `,
99
+ node: `
100
+ import { createServer } from 'node:http';
101
+
102
+ createServer(async (req, res) => {
103
+ const url = new URL(req.url ?? '/', \`http://\${req.headers.host}\`);
104
+ const body = await new Promise<Buffer>((resolve) => {
105
+ const chunks: Buffer[] = [];
106
+ req.on('data', (c: Buffer) => chunks.push(c));
107
+ req.on('end', () => resolve(Buffer.concat(chunks)));
108
+ });
109
+ const request = new Request(url.href, {
110
+ method: req.method,
111
+ headers: req.headers as Record<string, string>,
112
+ body: req.method !== 'GET' && req.method !== 'HEAD' ? body : undefined,
113
+ });
114
+ const response = await handler(request);
115
+ res.writeHead(response.status, Object.fromEntries(response.headers));
116
+ const buffer = Buffer.from(await response.arrayBuffer());
117
+ res.end(buffer);
118
+ }).listen(3000, () => {
119
+ console.log('🧃 Listening on http://localhost:3000');
120
+ });
121
+ `,
122
+ cloudflare: `
123
+ export default { fetch: handler };
124
+ `,
125
+ deno: `
126
+ Deno.serve({ port: 3000 }, handler);
127
+
128
+ console.log('🧃 Listening on http://localhost:3000');
129
+ `,
130
+ };
131
+ export function serverEntry(target) {
132
+ return SERVER_PREAMBLE + SERVER_ADAPTERS[target];
133
+ }
134
+ export function homeRoute() {
135
+ return `import React from 'react';
136
+
137
+ export default function HomePage() {
138
+ const timestamp = new Date().toISOString();
139
+
140
+ return (
141
+ <html>
142
+ <head>
143
+ <title>Juice App</title>
144
+ </head>
145
+ <body>
146
+ <h1>🧃 Juice</h1>
147
+ <p>Server-rendered at {timestamp}</p>
148
+ </body>
149
+ </html>
150
+ );
151
+ }
152
+ `;
153
+ }
154
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,kCAAkC;AAClC,mEAAmE;AACnE,oEAAoE;AAIpE,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAEtG,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,oBAAoB;IAChC,IAAI,EAAE,MAAM;CACb,CAAC;AAOF,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAmB;IAC3D,MAAM,WAAW,GAAiC;QAChD,GAAG,EAAE,eAAe;QACpB,IAAI,EAAE,qBAAqB;QAC3B,UAAU,EAAE,cAAc;QAC1B,IAAI,EAAE,6CAA6C;KACpD,CAAC;IAEF,MAAM,GAAG,GAA4B;QACnC,IAAI;QACJ,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,UAAU;YACf,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;YAC1B,SAAS,EAAE,cAAc;SAC1B;QACD,YAAY,EAAE;YACZ,YAAY,EAAE,QAAQ;YACtB,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,SAAS;SACvB;QACD,eAAe,EAAE;YACf,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,SAAS;YAC7B,UAAU,EAAE,QAAQ;YACpB,IAAI,EAAE,QAAQ;SACf;KACF,CAAC;IAEF,2DAA2D;IAC3D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACrB,GAAG,CAAC,eAA0C,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC;IAC7E,CAAC;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,MAAM,MAAM,GAAG;QACb,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,GAAG,EAAE,WAAW;YAChB,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,IAAI;YACrB,oBAAoB,EAAE,IAAI;SAC3B;QACD,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;KACjC,CAAC;IACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,mEAAmE;AAEnE,MAAM,eAAe,GAAG;;;;;;;;;;;;;;CAcvB,CAAC;AAEF,MAAM,eAAe,GAAiC;IACpD,GAAG,EAAE;;;;;;;CAON;IACC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsBP;IACC,UAAU,EAAE;;CAEb;IACC,IAAI,EAAE;;;;CAIP;CACA,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,MAAoB;IAC9C,OAAO,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO;;;;;;;;;;;;;;;;;CAiBR,CAAC;AACF,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Custom error classes for the Juice compiler.
3
+ *
4
+ * Every error provides:
5
+ * 1. **What** went wrong.
6
+ * 2. **Why** it went wrong.
7
+ * 3. **Exactly how to fix it.**
8
+ *
9
+ * @module errors
10
+ */
11
+ /**
12
+ * The two directive types supported by the Juice compiler.
13
+ */
14
+ export type DirectiveType = 'use client' | 'use server';
15
+ /**
16
+ * Thrown when a `'use client'` directive is found in an invalid position.
17
+ *
18
+ * @example
19
+ * ```
20
+ * JuiceDirectiveError: 'use client' must be the first statement in
21
+ * components/Counter.tsx. Found 'ImportDeclaration' at line 1 instead.
22
+ * Move the directive to the very first line of the file.
23
+ * ```
24
+ */
25
+ export declare class JuiceDirectiveError extends Error {
26
+ readonly name = "JuiceDirectiveError";
27
+ constructor(file: string, actualNodeType: string, line: number);
28
+ }
29
+ /**
30
+ * Thrown when a directive module exports nothing.
31
+ *
32
+ * @example
33
+ * ```
34
+ * JuiceExportError: components/Counter.tsx has a 'use client' directive
35
+ * but exports nothing. Directive modules must export at least one binding.
36
+ * Did you forget to add 'export default'?
37
+ * ```
38
+ */
39
+ export declare class JuiceExportError extends Error {
40
+ readonly name = "JuiceExportError";
41
+ constructor(file: string, directive?: DirectiveType);
42
+ }
43
+ /**
44
+ * Thrown when a module contains BOTH `'use client'` and `'use server'` directives.
45
+ *
46
+ * A module cannot be both a client component and a server action — they have
47
+ * fundamentally incompatible execution semantics. Split the code into two files.
48
+ *
49
+ * @example
50
+ * ```
51
+ * JuiceMutualExclusionError: components/Mixed.tsx contains both 'use client'
52
+ * and 'use server' directives. A module cannot be both. Split the client
53
+ * component and server action into separate files.
54
+ * ```
55
+ */
56
+ export declare class JuiceMutualExclusionError extends Error {
57
+ readonly name = "JuiceMutualExclusionError";
58
+ constructor(file: string);
59
+ }
60
+ /**
61
+ * Thrown when a directive module uses `export * from '...'` which is unsupported.
62
+ *
63
+ * React requires explicit exports for client/server boundary modules because
64
+ * each export becomes a separately addressable reference in the Flight protocol.
65
+ * Barrel re-exports (`export *`) lose the explicit mapping.
66
+ *
67
+ * @example
68
+ * ```
69
+ * JuiceBarrelExportError: components/index.tsx uses 'export * from' with
70
+ * a 'use client' directive. Only explicit named exports are allowed in
71
+ * directive modules. Replace with: export { Counter, Badge } from './Counter';
72
+ * ```
73
+ */
74
+ export declare class JuiceBarrelExportError extends Error {
75
+ readonly name = "JuiceBarrelExportError";
76
+ constructor(file: string, directive: DirectiveType, source: string);
77
+ }
78
+ /**
79
+ * Thrown when the Flight manifest cannot be written to disk.
80
+ *
81
+ * @example
82
+ * ```
83
+ * JuiceManifestError: Failed to write flight-manifest.json to dist/.
84
+ * Ensure the output directory exists and is writable. Path: /abs/dist/flight-manifest.json
85
+ * ```
86
+ */
87
+ export declare class JuiceManifestError extends Error {
88
+ readonly name = "JuiceManifestError";
89
+ constructor(outDir: string, fullPath: string, cause?: unknown);
90
+ }
91
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/compiler/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,YAAY,CAAC;AAExD;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAkB,IAAI,yBAAyB;gBAEnC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO/D;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;gBAEhC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,aAA4B;CAOlE;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,SAAkB,IAAI,+BAA+B;gBAEzC,IAAI,EAAE,MAAM;CAOzB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAkB,IAAI,4BAA4B;gBAEtC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;CASnE;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAkB,IAAI,wBAAwB;gBAElC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAQ9D"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Custom error classes for the Juice compiler.
3
+ *
4
+ * Every error provides:
5
+ * 1. **What** went wrong.
6
+ * 2. **Why** it went wrong.
7
+ * 3. **Exactly how to fix it.**
8
+ *
9
+ * @module errors
10
+ */
11
+ /**
12
+ * Thrown when a `'use client'` directive is found in an invalid position.
13
+ *
14
+ * @example
15
+ * ```
16
+ * JuiceDirectiveError: 'use client' must be the first statement in
17
+ * components/Counter.tsx. Found 'ImportDeclaration' at line 1 instead.
18
+ * Move the directive to the very first line of the file.
19
+ * ```
20
+ */
21
+ export class JuiceDirectiveError extends Error {
22
+ name = 'JuiceDirectiveError';
23
+ constructor(file, actualNodeType, line) {
24
+ super(`'use client' must be the first statement in ${file}. ` +
25
+ `Found '${actualNodeType}' at line ${line} instead. ` +
26
+ `Move the directive to the very first line of the file.`);
27
+ }
28
+ }
29
+ /**
30
+ * Thrown when a directive module exports nothing.
31
+ *
32
+ * @example
33
+ * ```
34
+ * JuiceExportError: components/Counter.tsx has a 'use client' directive
35
+ * but exports nothing. Directive modules must export at least one binding.
36
+ * Did you forget to add 'export default'?
37
+ * ```
38
+ */
39
+ export class JuiceExportError extends Error {
40
+ name = 'JuiceExportError';
41
+ constructor(file, directive = 'use client') {
42
+ super(`${file} has a '${directive}' directive but exports nothing. ` +
43
+ `Directive modules must export at least one binding. ` +
44
+ `Did you forget to add 'export default' or 'export function'?`);
45
+ }
46
+ }
47
+ /**
48
+ * Thrown when a module contains BOTH `'use client'` and `'use server'` directives.
49
+ *
50
+ * A module cannot be both a client component and a server action — they have
51
+ * fundamentally incompatible execution semantics. Split the code into two files.
52
+ *
53
+ * @example
54
+ * ```
55
+ * JuiceMutualExclusionError: components/Mixed.tsx contains both 'use client'
56
+ * and 'use server' directives. A module cannot be both. Split the client
57
+ * component and server action into separate files.
58
+ * ```
59
+ */
60
+ export class JuiceMutualExclusionError extends Error {
61
+ name = 'JuiceMutualExclusionError';
62
+ constructor(file) {
63
+ super(`${file} contains both 'use client' and 'use server' directives. ` +
64
+ `A module cannot be both a client component and a server action. ` +
65
+ `Split the client component and server action into separate files.`);
66
+ }
67
+ }
68
+ /**
69
+ * Thrown when a directive module uses `export * from '...'` which is unsupported.
70
+ *
71
+ * React requires explicit exports for client/server boundary modules because
72
+ * each export becomes a separately addressable reference in the Flight protocol.
73
+ * Barrel re-exports (`export *`) lose the explicit mapping.
74
+ *
75
+ * @example
76
+ * ```
77
+ * JuiceBarrelExportError: components/index.tsx uses 'export * from' with
78
+ * a 'use client' directive. Only explicit named exports are allowed in
79
+ * directive modules. Replace with: export { Counter, Badge } from './Counter';
80
+ * ```
81
+ */
82
+ export class JuiceBarrelExportError extends Error {
83
+ name = 'JuiceBarrelExportError';
84
+ constructor(file, directive, source) {
85
+ super(`${file} uses 'export * from ${JSON.stringify(source)}' with a ` +
86
+ `'${directive}' directive. Only explicit named exports are allowed ` +
87
+ `in directive modules because each export must be individually ` +
88
+ `addressable in the Flight protocol. ` +
89
+ `Replace with: export { SpecificExport } from ${JSON.stringify(source)};`);
90
+ }
91
+ }
92
+ /**
93
+ * Thrown when the Flight manifest cannot be written to disk.
94
+ *
95
+ * @example
96
+ * ```
97
+ * JuiceManifestError: Failed to write flight-manifest.json to dist/.
98
+ * Ensure the output directory exists and is writable. Path: /abs/dist/flight-manifest.json
99
+ * ```
100
+ */
101
+ export class JuiceManifestError extends Error {
102
+ name = 'JuiceManifestError';
103
+ constructor(outDir, fullPath, cause) {
104
+ super(`Failed to write flight-manifest.json to ${outDir}. ` +
105
+ `Ensure the output directory exists and is writable. ` +
106
+ `Path: ${fullPath}`);
107
+ this.cause = cause;
108
+ }
109
+ }
110
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/compiler/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;;;GASG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1B,IAAI,GAAG,qBAAqB,CAAC;IAE/C,YAAY,IAAY,EAAE,cAAsB,EAAE,IAAY;QAC5D,KAAK,CACH,+CAA+C,IAAI,IAAI;YACvD,UAAU,cAAc,aAAa,IAAI,YAAY;YACrD,wDAAwD,CACzD,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACvB,IAAI,GAAG,kBAAkB,CAAC;IAE5C,YAAY,IAAY,EAAE,YAA2B,YAAY;QAC/D,KAAK,CACH,GAAG,IAAI,WAAW,SAAS,mCAAmC;YAC9D,sDAAsD;YACtD,8DAA8D,CAC/D,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAChC,IAAI,GAAG,2BAA2B,CAAC;IAErD,YAAY,IAAY;QACtB,KAAK,CACH,GAAG,IAAI,2DAA2D;YAClE,kEAAkE;YAClE,mEAAmE,CACpE,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC7B,IAAI,GAAG,wBAAwB,CAAC;IAElD,YAAY,IAAY,EAAE,SAAwB,EAAE,MAAc;QAChE,KAAK,CACH,GAAG,IAAI,wBAAwB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW;YAChE,IAAI,SAAS,uDAAuD;YACpE,gEAAgE;YAChE,sCAAsC;YACtC,gDAAgD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAC1E,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACzB,IAAI,GAAG,oBAAoB,CAAC;IAE9C,YAAY,MAAc,EAAE,QAAgB,EAAE,KAAe;QAC3D,KAAK,CACH,2CAA2C,MAAM,IAAI;YACrD,sDAAsD;YACtD,SAAS,QAAQ,EAAE,CACpB,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Emits the `flight-manifest.json` file that maps server component references
3
+ * to client-side chunks.
4
+ *
5
+ * @module manifest
6
+ * @internal
7
+ */
8
+ import type { FlightManifest, ManifestRouteEntry } from './types.js';
9
+ import type { ClientModuleRegistry } from './registry.js';
10
+ import type { ServerActionRegistry } from './server-action-registry.js';
11
+ /**
12
+ * Build the {@link FlightManifest} object from the registries and resolved
13
+ * chunk file names.
14
+ *
15
+ * @param clientRegistry - The populated client module registry.
16
+ * @param chunkMap - Maps module specifiers to their emitted chunk file paths
17
+ * (e.g., `'components/Counter.tsx' → ['client/Counter.CxK3d.js']`).
18
+ * @param serverRegistry - Optional server action registry.
19
+ * @param routes - Optional route map (pattern → module info).
20
+ * @returns The complete manifest ready for JSON serialization.
21
+ *
22
+ * @internal
23
+ */
24
+ export declare function _buildManifest(clientRegistry: ClientModuleRegistry, chunkMap: ReadonlyMap<string, readonly string[]>, serverRegistry?: ServerActionRegistry, routes?: Readonly<Record<string, ManifestRouteEntry>>, meta?: FlightManifest['_meta']): FlightManifest;
25
+ /**
26
+ * Serialize the manifest to a human-readable JSON string.
27
+ *
28
+ * The output is intentionally pretty-printed (2-space indent) because the
29
+ * manifest is a build artifact consumed by the server runtime — human
30
+ * readability aids debugging and diffs. Size is irrelevant as it is never
31
+ * sent to clients.
32
+ *
33
+ * @param manifest - The manifest to serialize.
34
+ * @returns A JSON string with 2-space indentation.
35
+ *
36
+ * @internal
37
+ */
38
+ export declare function _serializeManifest(manifest: FlightManifest): string;
39
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/compiler/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,cAAc,EAGd,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,oBAAoB,EACpC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAChD,cAAc,CAAC,EAAE,oBAAoB,EACrC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,EACrD,IAAI,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,GAC7B,cAAc,CA6ChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAEnE"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Emits the `flight-manifest.json` file that maps server component references
3
+ * to client-side chunks.
4
+ *
5
+ * @module manifest
6
+ * @internal
7
+ */
8
+ /**
9
+ * Build the {@link FlightManifest} object from the registries and resolved
10
+ * chunk file names.
11
+ *
12
+ * @param clientRegistry - The populated client module registry.
13
+ * @param chunkMap - Maps module specifiers to their emitted chunk file paths
14
+ * (e.g., `'components/Counter.tsx' → ['client/Counter.CxK3d.js']`).
15
+ * @param serverRegistry - Optional server action registry.
16
+ * @param routes - Optional route map (pattern → module info).
17
+ * @returns The complete manifest ready for JSON serialization.
18
+ *
19
+ * @internal
20
+ */
21
+ export function _buildManifest(clientRegistry, chunkMap, serverRegistry, routes, meta) {
22
+ const clientModules = {};
23
+ for (const [specifier, info] of clientRegistry.entries()) {
24
+ const chunks = chunkMap.get(specifier) ?? [];
25
+ const exports = {};
26
+ for (const exp of info.exports) {
27
+ exports[exp.exportedName] = {
28
+ id: `${specifier}#${exp.exportedName}`,
29
+ name: exp.exportedName,
30
+ chunks: [...chunks],
31
+ };
32
+ }
33
+ clientModules[specifier] = {
34
+ chunks: [...chunks],
35
+ exports,
36
+ };
37
+ }
38
+ // Build server actions map — field names aligned with runtime ServerActionRef
39
+ const serverActions = {};
40
+ if (serverRegistry) {
41
+ for (const [specifier, info] of serverRegistry.entries()) {
42
+ for (const exp of info.exports) {
43
+ const actionId = `${specifier}#${exp.exportedName}`;
44
+ serverActions[actionId] = {
45
+ id: actionId,
46
+ exportName: exp.exportedName,
47
+ moduleId: specifier,
48
+ };
49
+ }
50
+ }
51
+ }
52
+ return {
53
+ $schema: 'https://juice.dev/schemas/flight-manifest.v1.json',
54
+ version: 1,
55
+ routes: routes ?? {},
56
+ clientModules,
57
+ ssrModules: {},
58
+ serverActions,
59
+ ...(meta ? { _meta: meta } : {}),
60
+ };
61
+ }
62
+ /**
63
+ * Serialize the manifest to a human-readable JSON string.
64
+ *
65
+ * The output is intentionally pretty-printed (2-space indent) because the
66
+ * manifest is a build artifact consumed by the server runtime — human
67
+ * readability aids debugging and diffs. Size is irrelevant as it is never
68
+ * sent to clients.
69
+ *
70
+ * @param manifest - The manifest to serialize.
71
+ * @returns A JSON string with 2-space indentation.
72
+ *
73
+ * @internal
74
+ */
75
+ export function _serializeManifest(manifest) {
76
+ return JSON.stringify(manifest, null, 2) + '\n';
77
+ }
78
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/compiler/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,cAAoC,EACpC,QAAgD,EAChD,cAAqC,EACrC,MAAqD,EACrD,IAA8B;IAE9B,MAAM,aAAa,GAAwC,EAAE,CAAC;IAE9D,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAE7C,MAAM,OAAO,GAAwC,EAAE,CAAC;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG;gBAC1B,EAAE,EAAE,GAAG,SAAS,IAAI,GAAG,CAAC,YAAY,EAAE;gBACtC,IAAI,EAAE,GAAG,CAAC,YAAY;gBACtB,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;aACpB,CAAC;QACJ,CAAC;QAED,aAAa,CAAC,SAAS,CAAC,GAAG;YACzB,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;YACnB,OAAO;SACR,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,MAAM,aAAa,GAA8C,EAAE,CAAC;IACpE,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;YACzD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;gBACpD,aAAa,CAAC,QAAQ,CAAC,GAAG;oBACxB,EAAE,EAAE,QAAQ;oBACZ,UAAU,EAAE,GAAG,CAAC,YAAY;oBAC5B,QAAQ,EAAE,SAAS;iBACpB,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,mDAAmD;QAC5D,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,MAAM,IAAI,EAAE;QACpB,aAAa;QACb,UAAU,EAAE,EAAE;QACd,aAAa;QACb,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAClD,CAAC"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * AST-based detection of `'use client'` and `'use server'` directives
3
+ * and export extraction.
4
+ *
5
+ * Uses Vite's built-in acorn parser via the Rollup plugin context — zero
6
+ * additional dependencies.
7
+ *
8
+ * @module parse
9
+ * @internal
10
+ */
11
+ import type { ExportRecord } from './types.js';
12
+ /**
13
+ * Quick check for the `'use client'` substring before doing a full AST parse.
14
+ * Returns `false` if the directive cannot possibly be present.
15
+ *
16
+ * @internal
17
+ */
18
+ export declare function _mayContainClientDirective(source: string): boolean;
19
+ /**
20
+ * Quick check for the `'use server'` substring before doing a full AST parse.
21
+ * Returns `false` if the directive cannot possibly be present.
22
+ *
23
+ * @internal
24
+ */
25
+ export declare function _mayContainServerDirective(source: string): boolean;
26
+ /**
27
+ * Quick check for either `'use client'` or `'use server'` substrings.
28
+ * Returns `false` if neither directive can possibly be present.
29
+ *
30
+ * @internal
31
+ */
32
+ export declare function _mayContainDirective(source: string): boolean;
33
+ /**
34
+ * Result of analyzing a module's AST for the `'use client'` directive.
35
+ *
36
+ * @internal
37
+ */
38
+ export type DirectiveResult = {
39
+ readonly hasDirective: false;
40
+ } | {
41
+ readonly hasDirective: true;
42
+ readonly exports: readonly ExportRecord[];
43
+ };
44
+ /**
45
+ * Analyze a parsed AST `Program` node for a `'use client'` directive and
46
+ * extract all exports if found.
47
+ *
48
+ * The directive MUST be the first statement in the module body (after optional
49
+ * comments). If `'use client'` appears anywhere other than position 0, this
50
+ * function returns `{ hasDirective: false }` — no false positives.
51
+ *
52
+ * @param ast - The acorn `Program` AST node (from `this.parse()` in Rollup context).
53
+ * @returns A {@link DirectiveResult} indicating whether the directive was found
54
+ * and, if so, all exports extracted from the module.
55
+ *
56
+ * @internal
57
+ */
58
+ export declare function _analyzeAST(ast: unknown): DirectiveResult;
59
+ /**
60
+ * Result of analyzing a module's AST for the `'use server'` directive.
61
+ *
62
+ * @internal
63
+ */
64
+ export type ServerDirectiveResult = {
65
+ readonly hasDirective: false;
66
+ } | {
67
+ readonly hasDirective: true;
68
+ readonly exports: readonly ExportRecord[];
69
+ };
70
+ /**
71
+ * Analyze a parsed AST `Program` node for a `'use server'` directive and
72
+ * extract all exports if found.
73
+ *
74
+ * The directive MUST be the first statement in the module body (after optional
75
+ * comments). If `'use server'` appears anywhere other than position 0, this
76
+ * function returns `{ hasDirective: false }` — no false positives.
77
+ *
78
+ * @param ast - The acorn `Program` AST node (from `this.parse()` in Rollup context).
79
+ * @returns A {@link ServerDirectiveResult} indicating whether the directive was found
80
+ * and, if so, all exports extracted from the module.
81
+ *
82
+ * @internal
83
+ */
84
+ export declare function _analyzeServerAST(ast: unknown): ServerDirectiveResult;
85
+ /**
86
+ * Detected directive type from a module's AST.
87
+ *
88
+ * @internal
89
+ */
90
+ export type DetectedDirective = 'use client' | 'use server' | null;
91
+ /**
92
+ * Unified result from `_detectDirective` — detects which directive (if any)
93
+ * is present and extracts exports, barrel re-export sources, and flags for
94
+ * mutual exclusion validation.
95
+ *
96
+ * @internal
97
+ */
98
+ export interface UnifiedDirectiveResult {
99
+ /** Which directive was detected, or `null` if none. */
100
+ readonly directive: DetectedDirective;
101
+ /** All explicit exports found in the module. */
102
+ readonly exports: readonly ExportRecord[];
103
+ /** Sources of any `export * from '...'` barrel re-exports. */
104
+ readonly barrelReExports: readonly string[];
105
+ /**
106
+ * Whether both `'use client'` and `'use server'` appear as directives
107
+ * in the AST. This is a fatal error condition.
108
+ */
109
+ readonly hasMutualExclusion: boolean;
110
+ }
111
+ /**
112
+ * Detect the directive (if any), extract exports, and perform validation
113
+ * checks in a single AST pass for the hardened pipeline.
114
+ *
115
+ * Advantages over calling `_analyzeAST` + `_analyzeServerAST` separately:
116
+ * - Single AST walk (not two)
117
+ * - Catches mutual exclusion (`'use client'` + `'use server'` simultaneously)
118
+ * - Detects barrel re-exports (`export *`) for a clear error
119
+ *
120
+ * @param ast - The acorn `Program` AST node.
121
+ * @returns A {@link UnifiedDirectiveResult} with all extracted information.
122
+ *
123
+ * @internal
124
+ */
125
+ export declare function _detectDirective(ast: unknown): UnifiedDirectiveResult;
126
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/compiler/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkE/C;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D;AAMD;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAiBzD;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,CAiBrE;AAMD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,YAAY,GAAG,IAAI,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAEtC,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAE1C,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAiDrE"}