@farm.js/plugin 0.1.0-beta.0 → 0.1.0-beta.10

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 (46) hide show
  1. package/package.json +14 -7
  2. package/dist/api/index.d.ts +0 -42
  3. package/dist/api/index.d.ts.map +0 -1
  4. package/dist/api/index.js +0 -567
  5. package/dist/context/index.d.ts +0 -61
  6. package/dist/context/index.d.ts.map +0 -1
  7. package/dist/context/index.js +0 -75
  8. package/dist/index.d.ts +0 -43
  9. package/dist/index.d.ts.map +0 -1
  10. package/dist/index.js +0 -49
  11. package/dist/middleware/index.d.ts +0 -97
  12. package/dist/middleware/index.d.ts.map +0 -1
  13. package/dist/middleware/index.js +0 -469
  14. package/dist/observability/index.d.ts +0 -190
  15. package/dist/observability/index.d.ts.map +0 -1
  16. package/dist/observability/index.js +0 -399
  17. package/dist/rsc/build-paths.d.ts +0 -3
  18. package/dist/rsc/build-paths.d.ts.map +0 -1
  19. package/dist/rsc/build-paths.js +0 -8
  20. package/dist/rsc/entries/client.d.ts +0 -14
  21. package/dist/rsc/entries/client.d.ts.map +0 -1
  22. package/dist/rsc/entries/client.js +0 -283
  23. package/dist/rsc/entries/rsc.d.ts +0 -13
  24. package/dist/rsc/entries/rsc.d.ts.map +0 -1
  25. package/dist/rsc/entries/rsc.js +0 -932
  26. package/dist/rsc/entries/ssr.d.ts +0 -13
  27. package/dist/rsc/entries/ssr.d.ts.map +0 -1
  28. package/dist/rsc/entries/ssr.js +0 -245
  29. package/dist/rsc/index.d.ts +0 -78
  30. package/dist/rsc/index.d.ts.map +0 -1
  31. package/dist/rsc/index.js +0 -1368
  32. package/dist/rsc/nitro-build.d.ts +0 -36
  33. package/dist/rsc/nitro-build.d.ts.map +0 -1
  34. package/dist/rsc/nitro-build.js +0 -396
  35. package/dist/rsc/optimized-boundary.d.ts +0 -20
  36. package/dist/rsc/optimized-boundary.d.ts.map +0 -1
  37. package/dist/rsc/optimized-boundary.js +0 -15
  38. package/dist/rsc/server-fn-transform.d.ts +0 -6
  39. package/dist/rsc/server-fn-transform.d.ts.map +0 -1
  40. package/dist/rsc/server-fn-transform.js +0 -152
  41. package/dist/rsc/types.d.ts +0 -123
  42. package/dist/rsc/types.d.ts.map +0 -1
  43. package/dist/rsc/types.js +0 -1
  44. package/dist/rsc/vite-plugin-nitro.d.ts +0 -33
  45. package/dist/rsc/vite-plugin-nitro.d.ts.map +0 -1
  46. package/dist/rsc/vite-plugin-nitro.js +0 -163
@@ -1,283 +0,0 @@
1
- /**
2
- * Generates the browser entry file.
3
- *
4
- * This entry file:
5
- * - Reads the embedded RSC payload from the HTML (via rsc-html-stream)
6
- * - Deserializes it to React elements
7
- * - Sets up client-side navigation (intercepts links, handles popstate)
8
- * - Registers server action callback if enabled
9
- * - Hydrates the page
10
- * - Listens for HMR updates from server components
11
- */
12
- export function generateClientEntry(ctx) {
13
- const debugLog = `// Debug disabled`;
14
- const globalStylesheetImport = ctx.globalCssPath
15
- ? `const farmGlobalStylesheets = import.meta.glob(${JSON.stringify(ctx.globalCssPath)}, {
16
- eager: true,
17
- import: 'default',
18
- query: '?url',
19
- });
20
- export const farmGlobalStylesheet = Object.values(farmGlobalStylesheets)[0];
21
- `
22
- : "";
23
- let imports = `${globalStylesheetImport}
24
- import React from 'react';
25
- import { hydrateRoot } from 'react-dom/client';
26
- import { createFromReadableStream } from '@vitejs/plugin-rsc/browser';
27
- import { rscStream } from 'rsc-html-stream/client';
28
- import {
29
- createFarmDeploymentMismatchError,
30
- createFarmDeploymentRequestHeaders,
31
- isFarmDeploymentMismatchResponse,
32
- } from '@farm.js/core/deployment';
33
- `;
34
- if (ctx.actionsEnabled) {
35
- imports += `import { setServerCallback, encodeReply, createTemporaryReferenceSet } from '@vitejs/plugin-rsc/browser';
36
- import { applyFarmCacheInvalidations } from '@farm.js/core/cache';
37
- import {
38
- beginFarmServerQueryAction,
39
- completeFarmServerQueryAction,
40
- } from '@farm.js/core/server-query/client';
41
- `;
42
- }
43
- // Module-level ref so the server-action callback can update UI (assigned in BrowserRoot useEffect).
44
- // Set __viteRscCallServer immediately so it's never undefined when other chunks call it (then replace with real impl).
45
- let actionSetup = "";
46
- if (ctx.actionsEnabled) {
47
- actionSetup = `
48
- // Ref for payload setter (used by server action callback and refetch)
49
- const setPayloadRef = { current: null };
50
-
51
- // Ensure __viteRscCallServer is a function before any other chunk may call it (avoids "is not a function")
52
- if (typeof globalThis.__viteRscCallServer !== 'function') {
53
- globalThis.__viteRscCallServer = () => Promise.reject(new Error('Farm.js: server actions not ready'));
54
- }
55
- // Register real callback (replaces placeholder above)
56
- setServerCallback(async (id, args) => {
57
- debug('Invoking server action:', id);
58
- const serverQueryInvocation = beginFarmServerQueryAction(id, args);
59
- const refs = createTemporaryReferenceSet();
60
- const body = await encodeReply(args, { temporaryReferences: refs });
61
- const headers = createFarmDeploymentRequestHeaders(farmDeploymentId, {
62
- 'x-farm-action-id': id,
63
- 'Accept': 'text/x-component',
64
- });
65
- if (typeof body === 'string') headers.set('Content-Type', 'text/plain; charset=utf-8');
66
- else if (!(body instanceof FormData)) headers.set('Content-Type', 'application/octet-stream');
67
- const res = await fetch(location.href, {
68
- method: 'POST',
69
- headers,
70
- body,
71
- cache: 'no-store',
72
- credentials: 'same-origin',
73
- redirect: 'error',
74
- });
75
- if (isFarmDeploymentMismatchResponse(res, farmDeploymentId)) {
76
- throw reportDeploymentMismatch(res);
77
- }
78
- if (!res.ok) {
79
- const text = await res.text();
80
- console.error('[Farm.js] Server action request failed:', res.status, text);
81
- throw new Error('Server action failed: ' + res.status);
82
- }
83
- let p;
84
- try {
85
- p = await createFromReadableStream(res.body, { temporaryReferences: refs });
86
- } catch (e) {
87
- console.error('[Farm.js] Failed to deserialize action response:', e);
88
- throw e;
89
- }
90
- const hasContent = p && (typeof p.root !== 'undefined' || typeof p.rootContent !== 'undefined');
91
- if (!hasContent) {
92
- console.error('[Farm.js] Action response missing payload.root / payload.rootContent');
93
- return;
94
- }
95
- setPayloadRef.current?.(p);
96
- applyFarmCacheInvalidations(p.returnValue?.invalidations);
97
- if (!p.returnValue || !p.returnValue.ok) {
98
- debug('Server action failed:', id);
99
- const error = new Error(p.returnValue?.data?.message || 'Server function failed');
100
- error.name = 'ServerActionError';
101
- throw error;
102
- }
103
- return completeFarmServerQueryAction(serverQueryInvocation, p.returnValue.data);
104
- });
105
- `;
106
- }
107
- else {
108
- actionSetup = `
109
- const setPayloadRef = { current: null };
110
- `;
111
- }
112
- return `${imports}
113
- ${actionSetup}
114
- const farmDeploymentId = ${JSON.stringify(ctx.deploymentId)};
115
-
116
- function reportDeploymentMismatch(response) {
117
- const error = createFarmDeploymentMismatchError(response, farmDeploymentId);
118
- globalThis.dispatchEvent?.(new CustomEvent('farm:deployment-mismatch', { detail: error }));
119
- return error;
120
- }
121
-
122
- // Debug logging helper
123
- function debug(...args) {
124
- ${debugLog}
125
- }
126
-
127
- async function main() {
128
- // Prevent double execution (e.g. script loaded twice)
129
- if (globalThis.__FARM_RSC_HYDRATED) return;
130
-
131
- debug('Starting client hydration');
132
-
133
- // Clean duplicate DOM as early as possible (server may have sent two blocks)
134
- const rootEl = document.getElementById('root');
135
- if (rootEl) {
136
- while (rootEl.children.length > 1) rootEl.lastElementChild.remove();
137
- while (rootEl.nextElementSibling) rootEl.nextElementSibling.remove();
138
- }
139
-
140
- // Deserialize the initial RSC payload embedded in HTML
141
- // rscStream extracts the payload from <script> tags added by SSR
142
- let initial;
143
- try {
144
- initial = await createFromReadableStream(rscStream);
145
- debug('Initial RSC payload deserialized');
146
- } catch (e) {
147
- console.error('[Farm.js] Failed to deserialize RSC payload:', e);
148
- return;
149
- }
150
-
151
- // Root component that manages RSC state
152
- function BrowserRoot() {
153
- const [payload, set] = React.useState(initial);
154
-
155
- // Expose setter for external updates (navigation, actions, HMR)
156
- React.useEffect(() => {
157
- setPayloadRef.current = (p) => React.startTransition(() => set(p));
158
- }, []);
159
-
160
- // Keep document metadata in sync when an RSC navigation swaps only #root.
161
- React.useEffect(() => {
162
- if (typeof payload.metadata?.title === 'string') {
163
- document.title = payload.metadata.title;
164
- } else {
165
- document.title = '';
166
- }
167
- let description = document.querySelector('meta[name="description"]');
168
- if (typeof payload.metadata?.description === 'string') {
169
- if (!description) {
170
- description = document.createElement('meta');
171
- description.setAttribute('name', 'description');
172
- document.head.appendChild(description);
173
- }
174
- description.setAttribute('content', payload.metadata.description);
175
- } else {
176
- description?.remove();
177
- }
178
- }, [payload.metadata?.title, payload.metadata?.description]);
179
-
180
- // Set up client-side navigation
181
- React.useEffect(() => {
182
- // Re-fetch RSC when URL changes
183
- const nav = () => refetch(location.href);
184
-
185
- // Handle browser back/forward
186
- window.addEventListener('popstate', nav);
187
-
188
- // Intercept link clicks for client-side navigation
189
- const handleClick = (e) => {
190
- const a = e.target.closest('a');
191
- if (a?.href && a.origin === location.origin && !a.download && !a.target) {
192
- // Check for special attributes that should skip SPA navigation
193
- if (a.hasAttribute('data-native') || a.hasAttribute('data-reload')) {
194
- return;
195
- }
196
-
197
- e.preventDefault();
198
- history.pushState(null, '', a.href);
199
- nav();
200
- }
201
- };
202
-
203
- document.addEventListener('click', handleClick, true);
204
-
205
- return () => {
206
- window.removeEventListener('popstate', nav);
207
- document.removeEventListener('click', handleClick, true);
208
- };
209
- }, []);
210
-
211
- // Never render payload.root (full document) on the client - it creates a second visible block (entire page duplicated below).
212
- // Only render rootContent (layout+page for #root).
213
- const content = payload.rootContent;
214
- if (content == null) {
215
- if (payload.root != null) console.warn('[Farm.js] payload.rootContent missing; not using payload.root to avoid duplicate block. Keys:', Object.keys(payload));
216
- return null;
217
- }
218
- return content;
219
- }
220
-
221
- // Fetch new RSC payload for a URL
222
- async function refetch(url) {
223
- debug('Fetching RSC for:', url);
224
-
225
- try {
226
- // Request RSC format instead of HTML
227
- const res = await fetch(url, {
228
- headers: createFarmDeploymentRequestHeaders(farmDeploymentId, {
229
- Accept: 'text/x-component',
230
- }),
231
- });
232
- if (isFarmDeploymentMismatchResponse(res, farmDeploymentId)) {
233
- reportDeploymentMismatch(res);
234
- location.assign(url);
235
- return;
236
- }
237
-
238
- if (!res.ok) {
239
- console.error('[Farm.js] RSC fetch failed:', res.status);
240
- // Fall back to full page navigation
241
- location.href = url;
242
- return;
243
- }
244
-
245
- const newPayload = await createFromReadableStream(res.body);
246
- setPayloadRef.current?.(newPayload);
247
- debug('RSC navigation complete');
248
- } catch (e) {
249
- console.error('[Farm.js] RSC navigation failed:', e);
250
- // Fall back to full page navigation
251
- location.href = url;
252
- }
253
- }
254
- const rootElForHydrate = document.getElementById('root');
255
- if (!rootElForHydrate) {
256
- console.error('[Farm.js] #root element not found');
257
- return;
258
- }
259
- // Final cleanup pass before hydrate (in case DOM changed during async)
260
- while (rootElForHydrate.children.length > 1) rootElForHydrate.lastElementChild.remove();
261
- while (rootElForHydrate.nextElementSibling) rootElForHydrate.nextElementSibling.remove();
262
- debug('Hydrating application');
263
- globalThis.__FARM_RSC_HYDRATED = true;
264
- hydrateRoot(rootElForHydrate, React.createElement(BrowserRoot), {
265
- formState: initial.formState,
266
- });
267
-
268
- // Handle HMR for server components
269
- // When server code changes, re-fetch and re-render
270
- if (import.meta.hot) {
271
- import.meta.hot.on('rsc:update', () => {
272
- debug('HMR update received, refetching...');
273
- refetch(location.href);
274
- });
275
- }
276
- }
277
-
278
- // Start the application
279
- main().catch((e) => {
280
- console.error('[Farm.js] Client initialization failed:', e);
281
- });
282
- `;
283
- }
@@ -1,13 +0,0 @@
1
- import type { EntryContext } from "../types.js";
2
- /**
3
- * Generates the RSC environment entry file.
4
- *
5
- * This entry file:
6
- * - Auto-discovers page files using import.meta.glob
7
- * - Implements file-based routing by matching URL paths to page files
8
- * - Handles server actions if enabled (decoding arguments, executing, returning results)
9
- * - Renders the React tree to an RSC stream
10
- * - Either returns the stream directly (for client navigation) or delegates to SSR (for initial page load)
11
- */
12
- export declare function generateRscEntry(ctx: EntryContext): string;
13
- //# sourceMappingURL=rsc.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rsc.d.ts","sourceRoot":"","sources":["../../../src/rsc/entries/rsc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAg7B1D"}