@rsc-kit/core 0.1.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 (200) hide show
  1. package/README.md +95 -0
  2. package/SECURITY.md +60 -0
  3. package/dist/action.d.ts +90 -0
  4. package/dist/action.d.ts.map +1 -0
  5. package/dist/action.js +137 -0
  6. package/dist/action.js.map +1 -0
  7. package/dist/build-rsc-vite.d.ts +39 -0
  8. package/dist/build-rsc-vite.d.ts.map +1 -0
  9. package/dist/build-rsc-vite.js +172 -0
  10. package/dist/build-rsc-vite.js.map +1 -0
  11. package/dist/cache.d.ts +25 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +108 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/cli.d.ts +2 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +85 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/compile.d.ts +55 -0
  20. package/dist/compile.d.ts.map +1 -0
  21. package/dist/compile.js +141 -0
  22. package/dist/compile.js.map +1 -0
  23. package/dist/devServer.d.ts +18 -0
  24. package/dist/devServer.d.ts.map +1 -0
  25. package/dist/devServer.js +70 -0
  26. package/dist/devServer.js.map +1 -0
  27. package/dist/devUrls.d.ts +11 -0
  28. package/dist/devUrls.d.ts.map +1 -0
  29. package/dist/devUrls.js +68 -0
  30. package/dist/devUrls.js.map +1 -0
  31. package/dist/embed.d.ts +21 -0
  32. package/dist/embed.d.ts.map +1 -0
  33. package/dist/embed.js +119 -0
  34. package/dist/embed.js.map +1 -0
  35. package/dist/errors.d.ts +24 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +38 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/export.d.ts +41 -0
  40. package/dist/export.d.ts.map +1 -0
  41. package/dist/export.js +100 -0
  42. package/dist/export.js.map +1 -0
  43. package/dist/files.d.ts +39 -0
  44. package/dist/files.d.ts.map +1 -0
  45. package/dist/files.js +146 -0
  46. package/dist/files.js.map +1 -0
  47. package/dist/headers.d.ts +81 -0
  48. package/dist/headers.d.ts.map +1 -0
  49. package/dist/headers.js +96 -0
  50. package/dist/headers.js.map +1 -0
  51. package/dist/host.d.ts +86 -0
  52. package/dist/host.d.ts.map +1 -0
  53. package/dist/host.js +590 -0
  54. package/dist/host.js.map +1 -0
  55. package/dist/js/ActivityRouter.d.ts +47 -0
  56. package/dist/js/ActivityRouter.d.ts.map +1 -0
  57. package/dist/js/ActivityRouter.js +87 -0
  58. package/dist/js/ActivityRouter.js.map +1 -0
  59. package/dist/js/DocumentTitle.d.ts +22 -0
  60. package/dist/js/DocumentTitle.d.ts.map +1 -0
  61. package/dist/js/DocumentTitle.js +28 -0
  62. package/dist/js/DocumentTitle.js.map +1 -0
  63. package/dist/js/Form.d.ts +54 -0
  64. package/dist/js/Form.d.ts.map +1 -0
  65. package/dist/js/Form.js +225 -0
  66. package/dist/js/Form.js.map +1 -0
  67. package/dist/js/Link.d.ts +29 -0
  68. package/dist/js/Link.d.ts.map +1 -0
  69. package/dist/js/Link.js +112 -0
  70. package/dist/js/Link.js.map +1 -0
  71. package/dist/js/PathnameProvider.d.ts +8 -0
  72. package/dist/js/PathnameProvider.d.ts.map +1 -0
  73. package/dist/js/PathnameProvider.js +24 -0
  74. package/dist/js/PathnameProvider.js.map +1 -0
  75. package/dist/js/RedirectBoundary.d.ts +18 -0
  76. package/dist/js/RedirectBoundary.d.ts.map +1 -0
  77. package/dist/js/RedirectBoundary.js +34 -0
  78. package/dist/js/RedirectBoundary.js.map +1 -0
  79. package/dist/js/SegmentBoundary.d.ts +8 -0
  80. package/dist/js/SegmentBoundary.d.ts.map +1 -0
  81. package/dist/js/SegmentBoundary.js +38 -0
  82. package/dist/js/SegmentBoundary.js.map +1 -0
  83. package/dist/js/SlotBoundary.d.ts +15 -0
  84. package/dist/js/SlotBoundary.d.ts.map +1 -0
  85. package/dist/js/SlotBoundary.js +17 -0
  86. package/dist/js/SlotBoundary.js.map +1 -0
  87. package/dist/js/createViteRscApp.d.ts +8 -0
  88. package/dist/js/createViteRscApp.d.ts.map +1 -0
  89. package/dist/js/createViteRscApp.js +185 -0
  90. package/dist/js/createViteRscApp.js.map +1 -0
  91. package/dist/js/errors.d.ts +51 -0
  92. package/dist/js/errors.d.ts.map +1 -0
  93. package/dist/js/errors.js +93 -0
  94. package/dist/js/errors.js.map +1 -0
  95. package/dist/js/navigate.d.ts +118 -0
  96. package/dist/js/navigate.d.ts.map +1 -0
  97. package/dist/js/navigate.js +780 -0
  98. package/dist/js/navigate.js.map +1 -0
  99. package/dist/js/onlineStore.d.ts +23 -0
  100. package/dist/js/onlineStore.d.ts.map +1 -0
  101. package/dist/js/onlineStore.js +42 -0
  102. package/dist/js/onlineStore.js.map +1 -0
  103. package/dist/js/pagePayload.d.ts +15 -0
  104. package/dist/js/pagePayload.d.ts.map +1 -0
  105. package/dist/js/pagePayload.js +39 -0
  106. package/dist/js/pagePayload.js.map +1 -0
  107. package/dist/js/router.d.ts +29 -0
  108. package/dist/js/router.d.ts.map +1 -0
  109. package/dist/js/router.js +40 -0
  110. package/dist/js/router.js.map +1 -0
  111. package/dist/js/section.d.ts +16 -0
  112. package/dist/js/section.d.ts.map +1 -0
  113. package/dist/js/section.js +55 -0
  114. package/dist/js/section.js.map +1 -0
  115. package/dist/js/segmentStore.d.ts +69 -0
  116. package/dist/js/segmentStore.d.ts.map +1 -0
  117. package/dist/js/segmentStore.js +127 -0
  118. package/dist/js/segmentStore.js.map +1 -0
  119. package/dist/js/slotStore.d.ts +35 -0
  120. package/dist/js/slotStore.d.ts.map +1 -0
  121. package/dist/js/slotStore.js +46 -0
  122. package/dist/js/slotStore.js.map +1 -0
  123. package/dist/js/standardSchema.d.ts +47 -0
  124. package/dist/js/standardSchema.d.ts.map +1 -0
  125. package/dist/js/standardSchema.js +41 -0
  126. package/dist/js/standardSchema.js.map +1 -0
  127. package/dist/js/useForm.d.ts +43 -0
  128. package/dist/js/useForm.d.ts.map +1 -0
  129. package/dist/js/useForm.js +164 -0
  130. package/dist/js/useForm.js.map +1 -0
  131. package/dist/js/useLinkStatus.d.ts +2 -0
  132. package/dist/js/useLinkStatus.d.ts.map +1 -0
  133. package/dist/js/useLinkStatus.js +3 -0
  134. package/dist/js/useLinkStatus.js.map +1 -0
  135. package/dist/js/useOnline.d.ts +8 -0
  136. package/dist/js/useOnline.d.ts.map +1 -0
  137. package/dist/js/useOnline.js +20 -0
  138. package/dist/js/useOnline.js.map +1 -0
  139. package/dist/js/usePathname.d.ts +9 -0
  140. package/dist/js/usePathname.d.ts.map +1 -0
  141. package/dist/js/usePathname.js +32 -0
  142. package/dist/js/usePathname.js.map +1 -0
  143. package/dist/js/useSearchParams.d.ts +2 -0
  144. package/dist/js/useSearchParams.d.ts.map +1 -0
  145. package/dist/js/useSearchParams.js +60 -0
  146. package/dist/js/useSearchParams.js.map +1 -0
  147. package/dist/manifest.d.ts +66 -0
  148. package/dist/manifest.d.ts.map +1 -0
  149. package/dist/manifest.js +13 -0
  150. package/dist/manifest.js.map +1 -0
  151. package/dist/prerender.d.ts +138 -0
  152. package/dist/prerender.d.ts.map +1 -0
  153. package/dist/prerender.js +387 -0
  154. package/dist/prerender.js.map +1 -0
  155. package/dist/redirect.d.ts +34 -0
  156. package/dist/redirect.d.ts.map +1 -0
  157. package/dist/redirect.js +108 -0
  158. package/dist/redirect.js.map +1 -0
  159. package/dist/redirectDigest.d.ts +20 -0
  160. package/dist/redirectDigest.d.ts.map +1 -0
  161. package/dist/redirectDigest.js +66 -0
  162. package/dist/redirectDigest.js.map +1 -0
  163. package/dist/request.d.ts +93 -0
  164. package/dist/request.d.ts.map +1 -0
  165. package/dist/request.js +308 -0
  166. package/dist/request.js.map +1 -0
  167. package/dist/revalidate.d.ts +43 -0
  168. package/dist/revalidate.d.ts.map +1 -0
  169. package/dist/revalidate.js +99 -0
  170. package/dist/revalidate.js.map +1 -0
  171. package/dist/routes.d.ts +37 -0
  172. package/dist/routes.d.ts.map +1 -0
  173. package/dist/routes.js +28 -0
  174. package/dist/routes.js.map +1 -0
  175. package/dist/routing.d.ts +52 -0
  176. package/dist/routing.d.ts.map +1 -0
  177. package/dist/routing.js +146 -0
  178. package/dist/routing.js.map +1 -0
  179. package/dist/runtime.d.ts +36 -0
  180. package/dist/runtime.d.ts.map +1 -0
  181. package/dist/runtime.js +86 -0
  182. package/dist/runtime.js.map +1 -0
  183. package/dist/safeUrl.d.ts +10 -0
  184. package/dist/safeUrl.d.ts.map +1 -0
  185. package/dist/safeUrl.js +40 -0
  186. package/dist/safeUrl.js.map +1 -0
  187. package/dist/streaming.d.ts +62 -0
  188. package/dist/streaming.d.ts.map +1 -0
  189. package/dist/streaming.js +108 -0
  190. package/dist/streaming.js.map +1 -0
  191. package/dist/types.d.ts +82 -0
  192. package/dist/vite.d.ts +109 -0
  193. package/dist/vite.d.ts.map +1 -0
  194. package/dist/vite.js +1909 -0
  195. package/dist/vite.js.map +1 -0
  196. package/dist/worker.d.ts +2 -0
  197. package/dist/worker.d.ts.map +1 -0
  198. package/dist/worker.js +863 -0
  199. package/dist/worker.js.map +1 -0
  200. package/package.json +223 -0
package/dist/cache.js ADDED
@@ -0,0 +1,108 @@
1
+ // Asking the same question twice in one request.
2
+ //
3
+ // import { cache } from '@rsc-kit/core/cache'
4
+ //
5
+ // export const currentUser = cache(async () => db.user(await sessionId()))
6
+ //
7
+ // A guard checks who you are; the layout wants their name; the page wants their
8
+ // permissions. Three calls, one request, one answer — without threading the
9
+ // result through props that only exist to carry it.
10
+ //
11
+ // This is the same shape as React's cache(), and deliberately not React's: the
12
+ // engine's own boundaries are not React's. A guard runs before any component
13
+ // does, which is exactly where the duplication starts, and React has no scope
14
+ // open there.
15
+ //
16
+ // Scoped to the request, so two in flight cannot see each other's answers. The
17
+ // scope is opened by whoever owns the request — the host, the worker, or the
18
+ // prerenderer — and everything below it shares one store.
19
+ import { resolveScope } from './revalidate.js';
20
+ const SCOPE = Symbol.for('@rsc-kit/core.cache-scope');
21
+ const globals = globalThis;
22
+ let ready = null;
23
+ function scope() {
24
+ return globals[SCOPE] ?? null;
25
+ }
26
+ function isObject(value) {
27
+ return (typeof value === 'object' && value !== null) || typeof value === 'function';
28
+ }
29
+ /** Walk to the node for this argument list, creating it as we go. */
30
+ function nodeFor(root, args) {
31
+ let node = root;
32
+ for (const arg of args) {
33
+ if (isObject(arg)) {
34
+ node.byIdentity ??= new WeakMap();
35
+ let next = node.byIdentity.get(arg);
36
+ if (!next) {
37
+ next = {};
38
+ node.byIdentity.set(arg, next);
39
+ }
40
+ node = next;
41
+ }
42
+ else {
43
+ node.byValue ??= new Map();
44
+ let next = node.byValue.get(arg);
45
+ if (!next) {
46
+ next = {};
47
+ node.byValue.set(arg, next);
48
+ }
49
+ node = next;
50
+ }
51
+ }
52
+ return node;
53
+ }
54
+ /**
55
+ * Memoise a function for the length of one request.
56
+ *
57
+ * The *promise* is cached, not the value, so callers that arrive while the
58
+ * first is still in flight wait on it rather than starting a second. A
59
+ * rejection is cached too: within one request the answer to a question does
60
+ * not change because you asked again.
61
+ *
62
+ * Outside a request this calls straight through. Nothing is stored, nothing
63
+ * leaks between requests, and shared code does not have to know which side of
64
+ * the boundary it is on — the same reason revalidate() is a no-op outside an
65
+ * action.
66
+ */
67
+ export function cache(fn) {
68
+ return (...args) => {
69
+ const store = scope()?.getStore();
70
+ if (!store)
71
+ return fn(...args);
72
+ let root = store.get(fn);
73
+ if (!root) {
74
+ root = {};
75
+ store.set(fn, root);
76
+ }
77
+ const node = nodeFor(root, args);
78
+ if (node.result)
79
+ return node.result.value;
80
+ const value = fn(...args);
81
+ node.result = { value };
82
+ return value;
83
+ };
84
+ }
85
+ /** Whether anything is listening, for code that wants to know. */
86
+ export function isCaching() {
87
+ return scope()?.getStore() !== undefined;
88
+ }
89
+ /**
90
+ * Run one request with a memo table of its own.
91
+ *
92
+ * Opened by whoever owns the request. Nesting is harmless and does not create a
93
+ * second table — an inner call reuses the one already open, so a host that
94
+ * wraps and an engine that also wraps do not end up with two.
95
+ */
96
+ export async function withCache(run) {
97
+ if (!globals[SCOPE]) {
98
+ ready ??= resolveScope().then((resolved) => {
99
+ globals[SCOPE] ??= resolved;
100
+ });
101
+ await ready;
102
+ }
103
+ const existing = scope().getStore();
104
+ if (existing)
105
+ return await run();
106
+ return await scope().run(new Map(), run);
107
+ }
108
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function runPrerender(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAsCA,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAchE"}
package/dist/cli.js ADDED
@@ -0,0 +1,85 @@
1
+ // The commands an app runs but should not have to own.
2
+ //
3
+ // `prerender` was a script every app copied: eleven lines of importing its own
4
+ // build output, clearing a directory and printing a table. Nothing in it was
5
+ // the app's decision, and a copy in every project is a copy that goes stale
6
+ // against the engine that produced it.
7
+ //
8
+ // What stays in the app is the server, because that genuinely differs, and
9
+ // export.ts when a site wants one, because where it writes is a real choice.
10
+ //
11
+ // Exported rather than executed: the command line lives in the rsc-kit package
12
+ // so that `bunx rsc-kit init` resolves with nothing installed, and this is the
13
+ // half of it that needs the engine.
14
+ import { rm } from 'node:fs/promises';
15
+ import { existsSync } from 'node:fs';
16
+ import { join, resolve } from 'node:path';
17
+ import { cwd, exit, stdout } from 'node:process';
18
+ import { prerender } from './prerender.js';
19
+ import { writeTo } from './files.js';
20
+ const HELP = `
21
+ rsc-kit — commands for an app built with @rsc-kit/core
22
+
23
+ Usage
24
+ rsc-kit prerender [options]
25
+
26
+ Options
27
+ --out <dir> where the build wrote its bundles (default: .rsc)
28
+ --static <dir> where to put the frozen pages (default: <out>/static)
29
+ -h, --help this
30
+
31
+ Run it after a build. Every page is attempted; a page that reaches for
32
+ request data at render time says so by doing it, and is left to render on
33
+ demand.
34
+ `;
35
+ export async function runPrerender(args) {
36
+ if (args.includes('--help') || args.includes('-h')) {
37
+ stdout.write(HELP);
38
+ return;
39
+ }
40
+ const flag = (name) => {
41
+ const i = args.indexOf(`--${name}`);
42
+ return i === -1 ? undefined : args[i + 1];
43
+ };
44
+ await prerenderWith(flag);
45
+ }
46
+ async function prerenderWith(flag) {
47
+ // Set before the engine is loaded, not by the caller. React's server build
48
+ // branches on this at module evaluation, so a production bundle evaluated
49
+ // without it behaves as a development one — which is why every app used to
50
+ // carry NODE_ENV in its scripts.
51
+ process.env.NODE_ENV ??= 'production';
52
+ const out = resolve(cwd(), flag('out') ?? '.rsc');
53
+ const staticDir = resolve(cwd(), flag('static') ?? join(out, 'static'));
54
+ const bundle = join(out, 'dist/rsc/index.js');
55
+ if (!existsSync(bundle)) {
56
+ stdout.write(`\n No build at ${bundle}.\n` +
57
+ ` Run the build first, or pass --out if it writes somewhere else.\n\n`);
58
+ exit(1);
59
+ }
60
+ // Imported after NODE_ENV is set, which a static import could not be.
61
+ const engine = (await import(bundle));
62
+ // Cleared first: a route that changes classification between builds
63
+ // otherwise leaves its old shell on disk and the host goes on serving it.
64
+ // Nothing warns — the page loads, with content from the previous build.
65
+ await rm(staticDir, { recursive: true, force: true });
66
+ const mark = { frozen: '○', shell: '◔', error: '✗' };
67
+ const results = await prerender({
68
+ engine,
69
+ write: writeTo(staticDir),
70
+ onResult: (r) => {
71
+ stdout.write(` ${mark[r.type] ?? ' '} ${r.url}${r.reason ? ` (${r.reason})` : ''}\n`);
72
+ if (r.warning)
73
+ stdout.write(` ⚠ ${r.warning}\n`);
74
+ },
75
+ });
76
+ const count = (type) => results.filter((r) => r.type === type).length;
77
+ stdout.write(`
78
+ ○ the whole page is stored
79
+ ◔ the chrome is stored; the rest is rendered per request
80
+
81
+ ${count('frozen')} stored, ${count('shell')} shells\n`);
82
+ if (count('error') > 0)
83
+ exit(1);
84
+ }
85
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ export interface CompileOptions {
2
+ /** The built engine bundle the worker loads. */
3
+ engine: string;
4
+ /** The browser build. */
5
+ assets: string;
6
+ /** What the prerenderer wrote, if it ran. */
7
+ prerendered?: string;
8
+ /** Where to put the binary. */
9
+ outfile: string;
10
+ /** Staging for the generated entry and asset module. */
11
+ workDir?: string;
12
+ /** The url prefix assets are served under. */
13
+ assetsPrefix?: string;
14
+ /** Default port, when PORT is unset. */
15
+ port?: number;
16
+ /**
17
+ * Strip names and whitespace. On by default.
18
+ *
19
+ * The server bundle is not read by anyone, so the only reason to turn it off
20
+ * is a stack trace you are trying to follow — and `sourcemap` covers that
21
+ * without giving up the size.
22
+ */
23
+ minify?: boolean;
24
+ /**
25
+ * Compile to bytecode ahead of time. On by default.
26
+ *
27
+ * Bun's claim is faster start-up; measured here it was 45ms against 48ms,
28
+ * which is inside the noise of this machine — so treat it as free rather
29
+ * than as a win. Its one real constraint is already met: the entry this
30
+ * generates has no top-level await, which bytecode refuses.
31
+ */
32
+ bytecode?: boolean;
33
+ /** 'linked' by default, so a stack trace in production points somewhere. */
34
+ sourcemap?: 'none' | 'linked' | 'inline' | 'external';
35
+ /**
36
+ * Build for another platform — `bun-linux-x64`, `bun-linux-arm64`,
37
+ * `bun-windows-x64`, `bun-darwin-arm64`.
38
+ *
39
+ * Bun downloads that platform's runtime the first time, so the first
40
+ * cross-compile is slow and later ones are not. Building a Linux binary from
41
+ * a Mac is the ordinary case for a deploy.
42
+ */
43
+ target?: string;
44
+ /**
45
+ * Anything else Bun.build takes, merged last.
46
+ *
47
+ * `compile` is merged key by key rather than replaced, so passing
48
+ * `{ compile: { windows: { hideConsole: true } } }` cannot accidentally drop
49
+ * the outfile — which is silently ignored if it moves to the top level.
50
+ */
51
+ bun?: Record<string, unknown>;
52
+ }
53
+ /** Build the binary. Returns where it was written. */
54
+ export declare function compile(options: CompileOptions): Promise<string>;
55
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;IACrD;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAwED,sDAAsD;AACtD,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAgEtE"}
@@ -0,0 +1,141 @@
1
+ // Compiling an app to a single Bun binary.
2
+ //
3
+ // `bun build --compile` follows imports and nothing else, so a host that reads
4
+ // its assets from a directory compiles to an executable that answers every
5
+ // route and 404s every stylesheet — served, unstyled, never hydrating, with
6
+ // nothing on the server side to say so.
7
+ //
8
+ // So this owns the whole step rather than asking an app to arrange it:
9
+ // generate the module that imports the assets, generate the entry that serves
10
+ // them, and run the compile. The app writes none of that, which matters
11
+ // because an entry importing embedded files is Bun-only — a shared one would
12
+ // break every Node and Workers deployment the same package supports.
13
+ //
14
+ // import { compile } from '@rsc-kit/core/compile'
15
+ //
16
+ // await compile({
17
+ // engine: './build/dist/rsc/index.js',
18
+ // assets: './build/public/assets',
19
+ // prerendered: './build/static',
20
+ // outfile: './app',
21
+ // })
22
+ import { mkdirSync, writeFileSync } from 'node:fs';
23
+ import { dirname, relative, resolve } from 'node:path';
24
+ import { writeEmbedModule } from './embed.js';
25
+ /**
26
+ * The entry, generated rather than written by the app.
27
+ *
28
+ * Assets become Bun.serve static routes, built once at boot: that is where the
29
+ * ETag, the 304 on a matching If-None-Match, and the route matching come from,
30
+ * none of which a per-request handler gets for free.
31
+ *
32
+ * No top-level await anywhere in it — an async IIFE instead — because
33
+ * `--bytecode` refuses a module that has one, and bytecode is most of the
34
+ * start-up win.
35
+ */
36
+ function entrySource(engineSpecifier, embedSpecifier, port) {
37
+ return `// GENERATED by @rsc-kit/core/compile — do not edit.
38
+ import { createRscHandler } from '@rsc-kit/core/host'
39
+ import * as engine from ${JSON.stringify(engineSpecifier)}
40
+ import { assetPaths, pagePaths, TYPES } from ${JSON.stringify(embedSpecifier)}
41
+
42
+ ;(async () => {
43
+ const rsc = createRscHandler({
44
+ engine,
45
+ // Reads what the binary carries. A miss falls through to rendering, the
46
+ // same as a partial prerender on disk.
47
+ prerendered: async (name) => {
48
+ const path = pagePaths[name]
49
+
50
+ return path ? await Bun.file(path).text() : null
51
+ },
52
+ })
53
+
54
+ // Built once, not per request. Aliases pointing at the same file share one
55
+ // Response so the bytes are held once.
56
+ const byPath = new Map()
57
+ const routes = {}
58
+
59
+ await Promise.all(
60
+ Object.entries(assetPaths).map(async ([url, path]) => {
61
+ let pending = byPath.get(path)
62
+
63
+ if (!pending) {
64
+ const file = Bun.file(path)
65
+
66
+ pending = file.bytes().then(
67
+ (bytes) =>
68
+ new Response(bytes, {
69
+ headers: {
70
+ 'Content-Type': TYPES[url.split('.').pop() ?? ''] ?? file.type ?? 'application/octet-stream',
71
+ // Content-hashed by the build, so this is safe.
72
+ 'Cache-Control': 'public, max-age=31536000, immutable',
73
+ },
74
+ }),
75
+ )
76
+
77
+ byPath.set(path, pending)
78
+ }
79
+
80
+ routes[url] = await pending
81
+ }),
82
+ )
83
+
84
+ const server = Bun.serve({
85
+ port: Number(Bun.env.PORT ?? ${port}),
86
+ routes,
87
+ fetch: async (request) => (await rsc(request)) ?? new Response('Not found', { status: 404 }),
88
+ })
89
+
90
+ console.log(\`listening on http://localhost:\${server.port}\`)
91
+ })()
92
+ `;
93
+ }
94
+ /** Build the binary. Returns where it was written. */
95
+ export async function compile(options) {
96
+ if (typeof Bun === 'undefined') {
97
+ throw new Error('compile() needs the Bun runtime — run it with `bun run`.');
98
+ }
99
+ const work = resolve(options.workDir ?? '.rsc-compile');
100
+ const embedFile = resolve(work, 'embedded.ts');
101
+ const entryFile = resolve(work, 'entry.ts');
102
+ const outfile = resolve(options.outfile);
103
+ mkdirSync(work, { recursive: true });
104
+ const found = writeEmbedModule({
105
+ assets: options.assets,
106
+ prerendered: options.prerendered,
107
+ out: embedFile,
108
+ prefix: options.assetsPrefix ?? '/assets/',
109
+ });
110
+ const specifier = (abs) => {
111
+ const rel = relative(work, resolve(abs)).replace(/\\/g, '/');
112
+ return rel.startsWith('.') ? rel : './' + rel;
113
+ };
114
+ writeFileSync(entryFile, entrySource(specifier(options.engine), './embedded.ts', options.port ?? 3000));
115
+ mkdirSync(dirname(outfile), { recursive: true });
116
+ const { compile: overrides, ...rest } = options.bun ?? {};
117
+ const result = await Bun.build({
118
+ entrypoints: [entryFile],
119
+ minify: options.minify ?? true,
120
+ sourcemap: options.sourcemap ?? 'linked',
121
+ bytecode: options.bytecode ?? true,
122
+ // Read at runtime by React to pick its build. Left unset, a production
123
+ // client is served a development payload: hydration fails, the page
124
+ // renders perfectly, and nothing is interactive or logged.
125
+ define: { 'process.env.NODE_ENV': JSON.stringify('production') },
126
+ ...rest,
127
+ // outfile has to live in here: a top-level one is ignored for a standalone
128
+ // build, and the binary lands somewhere else entirely.
129
+ compile: {
130
+ outfile,
131
+ ...(options.target ? { target: options.target } : {}),
132
+ ...(typeof overrides === 'object' ? overrides : {}),
133
+ },
134
+ });
135
+ if (!result.success) {
136
+ throw new Error(`Could not compile:\n${result.logs.map((l) => String(l)).join('\n')}`);
137
+ }
138
+ console.log(`compiled ${outfile} — ${found.assets} assets and ${found.prerendered} stored pages inside it`);
139
+ return outfile;
140
+ }
141
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.js","sourceRoot":"","sources":["../src/compile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface DevServerOptions {
2
+ /** Project root — where the app's vite config lives. */
3
+ projectRoot: string;
4
+ /** Config file to run. The build resolves this the same way. */
5
+ configFile: string;
6
+ /** Generated rsc entry to import through the runnable environment. */
7
+ entry: string;
8
+ /** Port to listen on. */
9
+ port: number;
10
+ }
11
+ export interface DevServer {
12
+ handler: Record<string, unknown>;
13
+ close: () => Promise<void>;
14
+ }
15
+ export declare function startDevServer(options: DevServerOptions): Promise<DevServer>;
16
+ /** Entry the dev server imports, matching where the plugin generates it. */
17
+ export declare function devEntryPath(outDir: string): string;
18
+ //# sourceMappingURL=devServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../src/devServer.ts"],"names":[],"mappings":"AAuCA,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,CAAC,CAoClF;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Vite dev server mode for the RSC worker.
3
+ *
4
+ * In a build the worker imports a bundled entry. Here it imports the entry
5
+ * through Vite's runnable `rsc` environment instead, so a source edit is
6
+ * picked up without a rebuild. The module shape is identical either way —
7
+ * installHostFn / handleRsc* / handleAction / resolveMetadata — so nothing
8
+ * downstream of the load knows which mode it is in.
9
+ *
10
+ * The host keeps serving the page; the dev server only answers module
11
+ * requests, which is the arrangement a Laravel developer already has with
12
+ * Vite. See devUrls.ts for how the browser is pointed at it.
13
+ */
14
+ import { createRequire } from 'node:module';
15
+ import { join } from 'node:path';
16
+ /**
17
+ * Vite resolved the way @vitejs/plugin-rsc resolves it.
18
+ *
19
+ * `isRunnableDevEnvironment` is an instanceof check, and plugin-rsc calls it
20
+ * against its own copy. Two copies of Vite — this package's and the app's, the
21
+ * ordinary case when the package is vendored rather than installed from npm —
22
+ * make a perfectly runnable environment report false, and the error names the
23
+ * environment rather than the duplication. A build never reaches that code
24
+ * path, so the mismatch is invisible until dev mode.
25
+ */
26
+ async function resolveViteAsPluginRscDoes() {
27
+ const here = createRequire(import.meta.url);
28
+ try {
29
+ const pluginRsc = here.resolve('@vitejs/plugin-rsc');
30
+ const fromPlugin = createRequire(pluginRsc);
31
+ return (await import(fromPlugin.resolve('vite')));
32
+ }
33
+ catch {
34
+ // Single copy, or a layout where plugin-rsc is not resolvable from here.
35
+ return (await import('vite'));
36
+ }
37
+ }
38
+ export async function startDevServer(options) {
39
+ const vite = await resolveViteAsPluginRscDoes();
40
+ const server = await vite.createServer({
41
+ root: options.projectRoot,
42
+ configFile: options.configFile,
43
+ server: {
44
+ port: options.port,
45
+ strictPort: true,
46
+ // The host serves the page from its own origin, so every module request
47
+ // is cross-origin. Dev only.
48
+ cors: true,
49
+ },
50
+ });
51
+ await server.listen();
52
+ const env = server.environments.rsc;
53
+ if (!env) {
54
+ await server.close();
55
+ throw new Error("[rsc-kit] no 'rsc' environment — is rscRoutes() in the vite config?");
56
+ }
57
+ if (!vite.isRunnableDevEnvironment(env)) {
58
+ await server.close();
59
+ throw new Error("[rsc-kit] the 'rsc' environment is not runnable.\n" +
60
+ 'This usually means two copies of Vite are installed and the plugin is ' +
61
+ 'checking against a different one than created this server.');
62
+ }
63
+ const handler = (await env.runner.import(options.entry));
64
+ return { handler, close: () => server.close() };
65
+ }
66
+ /** Entry the dev server imports, matching where the plugin generates it. */
67
+ export function devEntryPath(outDir) {
68
+ return join(outDir, '.gen', 'entry.rsc.tsx');
69
+ }
70
+ //# sourceMappingURL=devServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devServer.js","sourceRoot":"","sources":["../src/devServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC;;;;;;;;;GASG;AACH,KAAK,UAAU,0BAA0B;IACvC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;IAE3C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAA;QACpD,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;QAC3C,OAAO,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAA0B,CAAA;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,OAAO,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,CAA0B,CAAA;IACxD,CAAC;AACH,CAAC;AAkBD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAyB;IAC5D,MAAM,IAAI,GAAG,MAAM,0BAA0B,EAAE,CAAA;IAE/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;QACrC,IAAI,EAAE,OAAO,CAAC,WAAW;QACzB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE;YACN,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,IAAI;YAChB,wEAAwE;YACxE,6BAA6B;YAC7B,IAAI,EAAE,IAAI;SACX;KACF,CAAC,CAAA;IAEF,MAAM,MAAM,CAAC,MAAM,EAAE,CAAA;IAErB,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAA;IAEnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACpB,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAA;IACxF,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACpB,MAAM,IAAI,KAAK,CACb,oDAAoD;YAClD,wEAAwE;YACxE,4DAA4D,CAC/D,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAA4B,CAAA;IAEnF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAA;AACjD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,CAAA;AAC9C,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare function rewriteViteDevUrls(html: string, origin: string): string;
2
+ /**
3
+ * The same rewrite over a stream. A URL can straddle a chunk boundary, so the
4
+ * last few bytes are held back rather than emitted, and flushed at the end.
5
+ *
6
+ * Built from a reader rather than `pipeThrough(new TransformStream(...))`: the
7
+ * test suites share a process with happy-dom, which replaces the stream
8
+ * globals, and a foreign TransformStream is rejected by a native stream.
9
+ */
10
+ export declare function rewriteViteDevUrlStream(stream: ReadableStream, origin: string): ReadableStream;
11
+ //# sourceMappingURL=devUrls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devUrls.d.ts","sourceRoot":"","sources":["../src/devUrls.ts"],"names":[],"mappings":"AAqBA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CASvE;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAgC9F"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Dev-only rewriting of Vite's internal URLs onto the dev server's origin.
3
+ *
4
+ * In dev, @vitejs/plugin-rsc emits its bootstrap and CSS links root-relative —
5
+ * `/@id/...`, `/@fs/...`. It builds them as `config.base + url`, and Vite
6
+ * collapses an absolute `base` to `/` during dev, so neither `base` nor
7
+ * `server.origin` (the mechanism laravel-vite-plugin relies on) can move them.
8
+ *
9
+ * The host serves the page, so root-relative sends the browser to PHP for
10
+ * modules only Vite can answer. Rewriting them here keeps the app on its
11
+ * normal development URL while assets come from the dev server, which is the
12
+ * arrangement Laravel developers already expect from Vite.
13
+ *
14
+ * Only these four prefixes are rewritten. A blanket `/@` rule would also catch
15
+ * ordinary page text, and this runs over rendered HTML.
16
+ */
17
+ const VITE_PREFIXES = ['/@id/', '/@fs/', '/@vite/', '/@react-refresh'];
18
+ /** Longest tail that could hide a split prefix across a chunk boundary. */
19
+ const CARRY = Math.max(...VITE_PREFIXES.map((p) => p.length)) + 1;
20
+ export function rewriteViteDevUrls(html, origin) {
21
+ let out = html;
22
+ for (const prefix of VITE_PREFIXES) {
23
+ // Anchored on the opening quote so only URL positions match, never text
24
+ // that happens to contain the same characters.
25
+ out = out.split('"' + prefix).join('"' + origin + prefix);
26
+ out = out.split("'" + prefix).join("'" + origin + prefix);
27
+ }
28
+ return out;
29
+ }
30
+ /**
31
+ * The same rewrite over a stream. A URL can straddle a chunk boundary, so the
32
+ * last few bytes are held back rather than emitted, and flushed at the end.
33
+ *
34
+ * Built from a reader rather than `pipeThrough(new TransformStream(...))`: the
35
+ * test suites share a process with happy-dom, which replaces the stream
36
+ * globals, and a foreign TransformStream is rejected by a native stream.
37
+ */
38
+ export function rewriteViteDevUrlStream(stream, origin) {
39
+ const decoder = new TextDecoder();
40
+ const encoder = new TextEncoder();
41
+ const reader = stream.getReader();
42
+ let carry = '';
43
+ return new ReadableStream({
44
+ async pull(controller) {
45
+ while (true) {
46
+ const { done, value } = await reader.read();
47
+ if (done) {
48
+ if (carry)
49
+ controller.enqueue(encoder.encode(rewriteViteDevUrls(carry, origin)));
50
+ controller.close();
51
+ return;
52
+ }
53
+ const text = carry + decoder.decode(value, { stream: true });
54
+ // Hold back a possible partial prefix; emit everything before it.
55
+ const keep = Math.max(0, text.length - CARRY);
56
+ carry = text.slice(keep);
57
+ if (keep > 0) {
58
+ controller.enqueue(encoder.encode(rewriteViteDevUrls(text.slice(0, keep), origin)));
59
+ return;
60
+ }
61
+ }
62
+ },
63
+ cancel(reason) {
64
+ return reader.cancel(reason);
65
+ },
66
+ });
67
+ }
68
+ //# sourceMappingURL=devUrls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devUrls.js","sourceRoot":"","sources":["../src/devUrls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAA;AAEtE,2EAA2E;AAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAA;AAEjE,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAAc;IAC7D,IAAI,GAAG,GAAG,IAAI,CAAA;IACd,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACnC,wEAAwE;QACxE,+CAA+C;QAC/C,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,CAAA;QACzD,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAsB,EAAE,MAAc;IAC5E,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAA;IACjC,IAAI,KAAK,GAAG,EAAE,CAAA;IAEd,OAAO,IAAI,cAAc,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,UAAU;YACnB,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;gBAE3C,IAAI,IAAI,EAAE,CAAC;oBACT,IAAI,KAAK;wBAAE,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;oBAChF,UAAU,CAAC,KAAK,EAAE,CAAA;oBAClB,OAAM;gBACR,CAAC;gBAED,MAAM,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC5D,kEAAkE;gBAClE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAA;gBAC7C,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBAExB,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;oBACb,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;oBACnF,OAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,CAAC,MAAM;YACX,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC9B,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ export interface EmbedOptions {
2
+ /** The browser build — what `assetsDir` pointed at. */
3
+ assets?: string;
4
+ /** What the prerenderer wrote. */
5
+ prerendered?: string;
6
+ /** Where to write the generated module. */
7
+ out: string;
8
+ /** The url prefix assets are served under. */
9
+ prefix?: string;
10
+ }
11
+ /**
12
+ * Write the module that embeds the build.
13
+ *
14
+ * Returns what it found, so a build script can say so rather than producing a
15
+ * binary that is quietly missing half of itself.
16
+ */
17
+ export declare function writeEmbedModule(options: EmbedOptions): {
18
+ assets: number;
19
+ prerendered: number;
20
+ };
21
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAqBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqF/F"}