@analogjs/platform 2.6.4-beta.4 → 2.7.0-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/platform",
3
- "version": "2.6.4-beta.4",
3
+ "version": "2.7.0-beta.1",
4
4
  "description": "The fullstack meta-framework for Angular",
5
5
  "type": "module",
6
6
  "author": "Brandon Roberts <robertsbt@gmail.com>",
@@ -29,8 +29,9 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "nitropack": "^2.13.1",
32
- "@analogjs/vite-plugin-angular": "^2.6.4-beta.4",
33
- "@analogjs/vite-plugin-nitro": "^2.6.4-beta.4",
32
+ "@analogjs/vite-plugin-angular": "^2.7.0-beta.1",
33
+ "@analogjs/vite-plugin-nitro": "^2.7.0-beta.1",
34
+ "oxc-parser": "^0.121.0",
34
35
  "vitefu": "^1.1.2"
35
36
  },
36
37
  "peerDependencies": {
@@ -1,8 +1,11 @@
1
1
  import { normalizePath } from 'vite';
2
+ import { injectServerFnIds, serverFnFileId } from '@analogjs/vite-plugin-nitro';
3
+ import { scrubServerFnModule } from './server-fn-client-transform.js';
2
4
  export function clearClientPageEndpointsPlugin() {
5
+ let projectRoot = process.cwd();
6
+ let isBuild = true;
3
7
  return {
4
8
  name: 'analogjs-platform-clear-client-page-endpoint',
5
- apply: 'build',
6
9
  config() {
7
10
  return {
8
11
  build: {
@@ -17,10 +20,40 @@ export function clearClientPageEndpointsPlugin() {
17
20
  },
18
21
  };
19
22
  },
20
- transform(_code, id, options) {
21
- if (!options?.ssr &&
22
- id.includes(normalizePath('src/app/pages')) &&
23
- id.endsWith('.server.ts')) {
23
+ configResolved(config) {
24
+ projectRoot = config.root;
25
+ isBuild = config.command === 'build';
26
+ },
27
+ transform(code, id, options) {
28
+ if (!id.endsWith('.server.ts')) {
29
+ return;
30
+ }
31
+ // Server-function ids are derived from the project-root-relative path so
32
+ // the client proxy and the server registration always resolve to the same
33
+ // opaque, collision-free route.
34
+ const fileId = serverFnFileId(id, projectRoot);
35
+ if (options?.ssr) {
36
+ // SSR build keeps the real handlers but stamps the derived id into each
37
+ // serverFn config so it registers under the route the client calls.
38
+ const injected = injectServerFnIds(code, fileId);
39
+ return injected ? { code: injected.code, map: null } : undefined;
40
+ }
41
+ // Client build: a `.server.ts` defining server functions is rewritten to
42
+ // client-safe proxies (the `{ id, url, method }` refs the browser
43
+ // dispatches through); handlers and server imports are dropped so they
44
+ // tree-shake away.
45
+ const scrubbed = scrubServerFnModule(code, fileId);
46
+ if (scrubbed) {
47
+ // An empty mapping, not `null`: a null map lets the original module —
48
+ // handlers and all — survive in `sourcesContent` further down the
49
+ // pipeline, which would ship the server code to the browser after the
50
+ // scrub went to the trouble of removing it.
51
+ return { code: scrubbed.code, map: { mappings: '' } };
52
+ }
53
+ // Page load/action endpoints carry no client-consumable exports. Only the
54
+ // client build empties them; the dev server never pulls them into the
55
+ // browser graph, and emptying them there would break the SSR request.
56
+ if (isBuild && id.includes(normalizePath('src/app/pages'))) {
24
57
  return {
25
58
  code: 'export default undefined;',
26
59
  map: null,
@@ -30,4 +63,4 @@ export function clearClientPageEndpointsPlugin() {
30
63
  },
31
64
  };
32
65
  }
33
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xlYXItY2xpZW50LXBhZ2UtZW5kcG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9wbGF0Zm9ybS9zcmMvbGliL2NsZWFyLWNsaWVudC1wYWdlLWVuZHBvaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBVSxhQUFhLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFN0MsTUFBTSxVQUFVLDhCQUE4QjtJQUM1QyxPQUFPO1FBQ0wsSUFBSSxFQUFFLDhDQUE4QztRQUNwRCxLQUFLLEVBQUUsT0FBTztRQUNkLE1BQU07WUFDSixPQUFPO2dCQUNMLEtBQUssRUFBRTtvQkFDTCxhQUFhLEVBQUU7d0JBQ2IsTUFBTSxDQUFDLE9BQU87NEJBQ1osSUFDRSxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUM7Z0NBQ3ZDLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUNuQyxDQUFDO2dDQUNELE9BQU87NEJBQ1QsQ0FBQzt3QkFDSCxDQUFDO3FCQUNGO2lCQUNGO2FBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxTQUFTLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxPQUFPO1lBQzFCLElBQ0UsQ0FBQyxPQUFPLEVBQUUsR0FBRztnQkFDYixFQUFFLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDM0MsRUFBRSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsRUFDekIsQ0FBQztnQkFDRCxPQUFPO29CQUNMLElBQUksRUFBRSwyQkFBMkI7b0JBQ2pDLEdBQUcsRUFBRSxJQUFJO2lCQUNWLENBQUM7WUFDSixDQUFDO1lBRUQsT0FBTztRQUNULENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyJ9
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xlYXItY2xpZW50LXBhZ2UtZW5kcG9pbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9wbGF0Zm9ybS9zcmMvbGliL2NsZWFyLWNsaWVudC1wYWdlLWVuZHBvaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBVSxhQUFhLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGNBQWMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRWhGLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRXRFLE1BQU0sVUFBVSw4QkFBOEI7SUFDNUMsSUFBSSxXQUFXLEdBQUcsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ2hDLElBQUksT0FBTyxHQUFHLElBQUksQ0FBQztJQUVuQixPQUFPO1FBQ0wsSUFBSSxFQUFFLDhDQUE4QztRQUNwRCxNQUFNO1lBQ0osT0FBTztnQkFDTCxLQUFLLEVBQUU7b0JBQ0wsYUFBYSxFQUFFO3dCQUNiLE1BQU0sQ0FBQyxPQUFPOzRCQUNaLElBQ0UsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDO2dDQUN2QyxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFDbkMsQ0FBQztnQ0FDRCxPQUFPOzRCQUNULENBQUM7d0JBQ0gsQ0FBQztxQkFDRjtpQkFDRjthQUNGLENBQUM7UUFDSixDQUFDO1FBQ0QsY0FBYyxDQUFDLE1BQU07WUFDbkIsV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDMUIsT0FBTyxHQUFHLE1BQU0sQ0FBQyxPQUFPLEtBQUssT0FBTyxDQUFDO1FBQ3ZDLENBQUM7UUFDRCxTQUFTLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxPQUFPO1lBQ3pCLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7Z0JBQy9CLE9BQU87WUFDVCxDQUFDO1lBRUQseUVBQXlFO1lBQ3pFLDBFQUEwRTtZQUMxRSxnQ0FBZ0M7WUFDaEMsTUFBTSxNQUFNLEdBQUcsY0FBYyxDQUFDLEVBQUUsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUUvQyxJQUFJLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQztnQkFDakIsd0VBQXdFO2dCQUN4RSxvRUFBb0U7Z0JBQ3BFLE1BQU0sUUFBUSxHQUFHLGlCQUFpQixDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsT0FBTyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDbkUsQ0FBQztZQUVELHlFQUF5RTtZQUN6RSxrRUFBa0U7WUFDbEUsdUVBQXVFO1lBQ3ZFLG1CQUFtQjtZQUNuQixNQUFNLFFBQVEsR0FBRyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDbkQsSUFBSSxRQUFRLEVBQUUsQ0FBQztnQkFDYixzRUFBc0U7Z0JBQ3RFLGtFQUFrRTtnQkFDbEUsc0VBQXNFO2dCQUN0RSw0Q0FBNEM7Z0JBQzVDLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQztZQUN4RCxDQUFDO1lBRUQsMEVBQTBFO1lBQzFFLHNFQUFzRTtZQUN0RSxzRUFBc0U7WUFDdEUsSUFBSSxPQUFPLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsZUFBZSxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUMzRCxPQUFPO29CQUNMLElBQUksRUFBRSwyQkFBMkI7b0JBQ2pDLEdBQUcsRUFBRSxJQUFJO2lCQUNWLENBQUM7WUFDSixDQUFDO1lBRUQsT0FBTztRQUNULENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyJ9
@@ -1,10 +1,10 @@
1
1
  export declare const V18_X_NX_DEVKIT = "^20.0.0";
2
2
  export declare const V18_X_NX_ANGULAR = "^20.0.0";
3
- export declare const V18_X_ANALOG_JS_CONTENT = "^2.6.4-beta.4";
4
- export declare const V18_X_ANALOG_JS_ROUTER = "^2.6.4-beta.4";
3
+ export declare const V18_X_ANALOG_JS_CONTENT = "^2.7.0-beta.1";
4
+ export declare const V18_X_ANALOG_JS_ROUTER = "^2.7.0-beta.1";
5
5
  export declare const V18_X_ANALOG_JS_TRPC = "~0.4.0";
6
- export declare const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^2.6.4-beta.4";
7
- export declare const V18_X_ANALOG_JS_VITEST_ANGULAR = "^2.6.4-beta.4";
6
+ export declare const V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^2.7.0-beta.1";
7
+ export declare const V18_X_ANALOG_JS_VITEST_ANGULAR = "^2.7.0-beta.1";
8
8
  export declare const V18_X_TRPC_CLIENT = "^10.25.0";
9
9
  export declare const V18_X_TRPC_SERVER = "^10.25.0";
10
10
  export declare const V18_X_ISOMORPHIC_FETCH = "^3.0.0";
@@ -20,7 +20,7 @@ export declare const V18_X_TAILWINDCSS = "^4.1.4";
20
20
  export declare const V18_X_TAILWINDCSS_VITE = "^4.1.4";
21
21
  export declare const V18_X_POSTCSS = "^8.5.3";
22
22
  export declare const V18_X_AUTOPREFIXER = "^10.4.0";
23
- export declare const V18_X_ANALOG_JS_PLATFORM = "^2.6.4-beta.4";
23
+ export declare const V18_X_ANALOG_JS_PLATFORM = "^2.7.0-beta.1";
24
24
  export declare const V18_X_ANGULAR_DEVKIT_BUILD_ANGULAR = "^19.0.0";
25
25
  export declare const V18_X_NX_VITE = "^21.0.0";
26
26
  export declare const V18_X_NX_LINTER = "^21.0.0";
@@ -5,11 +5,11 @@ exports.V18_X_ZOD = exports.V18_X_VITEST = exports.V18_X_VITE_TSCONFIG_PATHS = e
5
5
  // dependencies
6
6
  exports.V18_X_NX_DEVKIT = '^20.0.0';
7
7
  exports.V18_X_NX_ANGULAR = '^20.0.0';
8
- exports.V18_X_ANALOG_JS_CONTENT = '^2.6.4-beta.4';
9
- exports.V18_X_ANALOG_JS_ROUTER = '^2.6.4-beta.4';
8
+ exports.V18_X_ANALOG_JS_CONTENT = '^2.7.0-beta.1';
9
+ exports.V18_X_ANALOG_JS_ROUTER = '^2.7.0-beta.1';
10
10
  exports.V18_X_ANALOG_JS_TRPC = '~0.4.0';
11
- exports.V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^2.6.4-beta.4';
12
- exports.V18_X_ANALOG_JS_VITEST_ANGULAR = '^2.6.4-beta.4';
11
+ exports.V18_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^2.7.0-beta.1';
12
+ exports.V18_X_ANALOG_JS_VITEST_ANGULAR = '^2.7.0-beta.1';
13
13
  exports.V18_X_TRPC_CLIENT = '^10.25.0';
14
14
  exports.V18_X_TRPC_SERVER = '^10.25.0';
15
15
  exports.V18_X_ISOMORPHIC_FETCH = '^3.0.0';
@@ -26,7 +26,7 @@ exports.V18_X_TAILWINDCSS_VITE = '^4.1.4';
26
26
  exports.V18_X_POSTCSS = '^8.5.3';
27
27
  exports.V18_X_AUTOPREFIXER = '^10.4.0';
28
28
  // devDependencies
29
- exports.V18_X_ANALOG_JS_PLATFORM = '^2.6.4-beta.4';
29
+ exports.V18_X_ANALOG_JS_PLATFORM = '^2.7.0-beta.1';
30
30
  exports.V18_X_ANGULAR_DEVKIT_BUILD_ANGULAR = '^19.0.0';
31
31
  exports.V18_X_NX_VITE = '^21.0.0';
32
32
  exports.V18_X_NX_LINTER = '^21.0.0';
@@ -1,13 +1,13 @@
1
- export declare const V19_X_ANALOG_JS_ROUTER = "^2.6.4-beta.4";
2
- export declare const V19_X_ANALOG_JS_CONTENT = "^2.6.4-beta.4";
1
+ export declare const V19_X_ANALOG_JS_ROUTER = "^2.7.0-beta.1";
2
+ export declare const V19_X_ANALOG_JS_CONTENT = "^2.7.0-beta.1";
3
3
  export declare const V19_X_MARKED = "^15.0.7";
4
4
  export declare const V19_X_MARKED_GFM_HEADING_ID = "^4.1.1";
5
5
  export declare const V19_X_MARKED_HIGHLIGHT = "^2.2.1";
6
6
  export declare const V19_X_MARKED_MANGLE = "^1.1.10";
7
7
  export declare const V19_X_PRISMJS = "^1.29.0";
8
- export declare const V19_X_ANALOG_JS_PLATFORM = "^2.6.4-beta.4";
9
- export declare const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^2.6.4-beta.4";
10
- export declare const V19_X_ANALOG_JS_VITEST_ANGULAR = "^2.6.4-beta.4";
8
+ export declare const V19_X_ANALOG_JS_PLATFORM = "^2.7.0-beta.1";
9
+ export declare const V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = "^2.7.0-beta.1";
10
+ export declare const V19_X_ANALOG_JS_VITEST_ANGULAR = "^2.7.0-beta.1";
11
11
  export declare const V19_X_NX_ANGULAR = "^22.0.0";
12
12
  export declare const V19_X_NX_VITE = "^22.0.0";
13
13
  export declare const V19_X_JSDOM = "^22.0.0";
@@ -2,17 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NX_X_LATEST_NX = exports.NX_X_LATEST_VITEST = exports.NX_X_LATEST_VITE = exports.V19_X_VITE = exports.V19_X_VITEST = exports.V19_X_VITE_TSCONFIG_PATHS = exports.V19_X_JSDOM = exports.V19_X_NX_VITE = exports.V19_X_NX_ANGULAR = exports.V19_X_ANALOG_JS_VITEST_ANGULAR = exports.V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = exports.V19_X_ANALOG_JS_PLATFORM = exports.V19_X_PRISMJS = exports.V19_X_MARKED_MANGLE = exports.V19_X_MARKED_HIGHLIGHT = exports.V19_X_MARKED_GFM_HEADING_ID = exports.V19_X_MARKED = exports.V19_X_ANALOG_JS_CONTENT = exports.V19_X_ANALOG_JS_ROUTER = void 0;
4
4
  // V19_X
5
- exports.V19_X_ANALOG_JS_ROUTER = '^2.6.4-beta.4';
6
- exports.V19_X_ANALOG_JS_CONTENT = '^2.6.4-beta.4';
5
+ exports.V19_X_ANALOG_JS_ROUTER = '^2.7.0-beta.1';
6
+ exports.V19_X_ANALOG_JS_CONTENT = '^2.7.0-beta.1';
7
7
  exports.V19_X_MARKED = '^15.0.7';
8
8
  exports.V19_X_MARKED_GFM_HEADING_ID = '^4.1.1';
9
9
  exports.V19_X_MARKED_HIGHLIGHT = '^2.2.1';
10
10
  exports.V19_X_MARKED_MANGLE = '^1.1.10';
11
11
  exports.V19_X_PRISMJS = '^1.29.0';
12
12
  // devDependencies
13
- exports.V19_X_ANALOG_JS_PLATFORM = '^2.6.4-beta.4';
14
- exports.V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^2.6.4-beta.4';
15
- exports.V19_X_ANALOG_JS_VITEST_ANGULAR = '^2.6.4-beta.4';
13
+ exports.V19_X_ANALOG_JS_PLATFORM = '^2.7.0-beta.1';
14
+ exports.V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR = '^2.7.0-beta.1';
15
+ exports.V19_X_ANALOG_JS_VITEST_ANGULAR = '^2.7.0-beta.1';
16
16
  exports.V19_X_NX_ANGULAR = '^22.0.0';
17
17
  exports.V19_X_NX_VITE = '^22.0.0';
18
18
  exports.V19_X_JSDOM = '^22.0.0';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Client-build scrub + proxy generation for server functions.
3
+ *
4
+ * On the client build a `*.server.ts` module must not carry server handler
5
+ * bodies (which `inject()` server services, read the request, hit the database).
6
+ * But the client still imports the named `serverFn` exports to dispatch them.
7
+ * This transform regenerates the module so each `export const NAME = serverFn(
8
+ * config, handler)` becomes a call to the client-safe `createServerFnRef`
9
+ * factory — keeping the `{ id, url, method }` metadata `injectServerFn` needs,
10
+ * dropping the handler and every server-only import. Because the regenerated
11
+ * module references nothing else, the server code tree-shakes away entirely.
12
+ *
13
+ * Returns the new module source, or `null` when the module defines no server
14
+ * function (the caller falls back to the page-endpoint scrub for those).
15
+ */
16
+ export interface ServerFnProxy {
17
+ name: string;
18
+ id: string;
19
+ method: 'GET' | 'POST';
20
+ }
21
+ export interface ScrubResult {
22
+ code: string;
23
+ proxies: ServerFnProxy[];
24
+ hadDefaultExport: boolean;
25
+ }
26
+ export declare function scrubServerFnModule(code: string, fileId?: string): ScrubResult | null;
@@ -0,0 +1,148 @@
1
+ import { parseSync } from 'oxc-parser';
2
+ // Light subpath (no vite/nitro barrel): the built scrub is loaded outside a
3
+ // build too, so it must not pull the plugin graph in.
4
+ import { deriveServerFnId } from '@analogjs/vite-plugin-nitro/server-fn-id';
5
+ const SERVER_FN_SOURCE = '@analogjs/router/server';
6
+ export function scrubServerFnModule(code, fileId = 'file.ts') {
7
+ // Cheap bail-out before parsing: no `serverFn` token, nothing to do.
8
+ if (!code.includes('serverFn')) {
9
+ return null;
10
+ }
11
+ const { program } = parseSync(fileId, code);
12
+ const body = program.body;
13
+ const serverFnLocalNames = collectServerFnLocalNames(body);
14
+ const hadDefaultExport = body.some((node) => node.type === 'ExportDefaultDeclaration');
15
+ const proxies = [];
16
+ for (const node of body) {
17
+ if (node.type !== 'ExportNamedDeclaration' ||
18
+ node.declaration?.type !== 'VariableDeclaration') {
19
+ continue;
20
+ }
21
+ for (const declarator of node.declaration.declarations) {
22
+ if (declarator.id?.type !== 'Identifier' ||
23
+ declarator.init?.type !== 'CallExpression' ||
24
+ declarator.init.callee?.type !== 'Identifier' ||
25
+ !serverFnLocalNames.has(declarator.init.callee.name)) {
26
+ continue;
27
+ }
28
+ proxies.push(toProxy(declarator.id.name, declarator.init.arguments ?? [], fileId));
29
+ }
30
+ }
31
+ // Every `serverFn(...)` call in the module must have become a proxy. If one
32
+ // did not, the module uses a shape this transform cannot rewrite (e.g.
33
+ // `const fn = serverFn(...); export { fn };`) and returning `null` would leave
34
+ // it untouched — shipping the handler and its server imports to the browser.
35
+ // Fail the build instead: a scrub that silently opts out is a code leak.
36
+ const callCount = countServerFnCalls(program, serverFnLocalNames);
37
+ if (callCount > proxies.length) {
38
+ throw new Error(`[analog] ${fileId}: found ${callCount} serverFn call(s) but could only rewrite ${proxies.length} for the client build. ` +
39
+ `Server functions must be declared as a directly exported const — \`export const name = serverFn(…)\` — so the handler can be stripped from the browser bundle.`);
40
+ }
41
+ if (proxies.length === 0) {
42
+ return null;
43
+ }
44
+ const lines = [
45
+ `import { createServerFnRef } from '@analogjs/router';`,
46
+ '',
47
+ ...proxies.map((p) => `export const ${p.name} = createServerFnRef({ id: ${JSON.stringify(p.id)}, method: ${JSON.stringify(p.method)} });`),
48
+ ];
49
+ // A file that is also a page endpoint keeps the load-shim the router expects.
50
+ if (hadDefaultExport) {
51
+ lines.push('', 'export default undefined;');
52
+ }
53
+ return { code: lines.join('\n') + '\n', proxies, hadDefaultExport };
54
+ }
55
+ /** Local identifier(s) `serverFn` is imported under from `@analogjs/router/server`. */
56
+ function collectServerFnLocalNames(body) {
57
+ const names = new Set();
58
+ for (const node of body) {
59
+ if (node.type !== 'ImportDeclaration' ||
60
+ node.source?.value !== SERVER_FN_SOURCE) {
61
+ continue;
62
+ }
63
+ for (const spec of node.specifiers ?? []) {
64
+ if (spec.type === 'ImportSpecifier' &&
65
+ spec.imported?.name === 'serverFn') {
66
+ names.add(spec.local.name);
67
+ }
68
+ }
69
+ }
70
+ // Fallback: if the module never imported it (unusual), still match the
71
+ // conventional name so a mis-resolved import doesn't leak server code.
72
+ if (names.size === 0) {
73
+ names.add('serverFn');
74
+ }
75
+ return names;
76
+ }
77
+ function toProxy(name, args, fileId) {
78
+ const method = methodForCall(name, args, fileId);
79
+ // The id is derived, never read from source — same algorithm the server
80
+ // registration uses, so client proxy and server route always match.
81
+ return { name, id: deriveServerFnId(fileId, name), method };
82
+ }
83
+ /**
84
+ * Resolve the HTTP method from the call shape, matching the runtime overloads:
85
+ * `serverFn(handler)` ⇒ GET, `serverFn(schema, handler)` ⇒ POST,
86
+ * `serverFn(config, handler)` ⇒ config-driven.
87
+ */
88
+ function methodForCall(name, args, fileId) {
89
+ const arg0 = args[0];
90
+ // serverFn(handler) — input-less GET.
91
+ if (isFunctionNode(arg0))
92
+ return 'GET';
93
+ // serverFn(config, handler) — read method/input off the object.
94
+ if (arg0?.type === 'ObjectExpression') {
95
+ let method;
96
+ let hasInput = false;
97
+ for (const prop of arg0.properties ?? []) {
98
+ if (prop.type !== 'Property')
99
+ continue;
100
+ const key = prop.key?.type === 'Identifier' ? prop.key.name : prop.key?.value;
101
+ if (key === 'method' && isStringLiteral(prop.value)) {
102
+ method = prop.value.value;
103
+ }
104
+ else if (key === 'input') {
105
+ hasInput = true;
106
+ }
107
+ }
108
+ if (method === 'GET' && hasInput) {
109
+ throw new Error(`[analog] serverFn "${name}" in ${fileId} declares method: 'GET' with an input schema; GET carries no body. Use POST or drop the input.`);
110
+ }
111
+ return method ?? (hasInput ? 'POST' : 'GET');
112
+ }
113
+ // serverFn(schema, handler) — a schema ⇒ POST + input.
114
+ if (arg0 && args.length >= 2)
115
+ return 'POST';
116
+ throw new Error(`[analog] serverFn "${name}" in ${fileId} must be called as serverFn(handler), serverFn(schema, handler), or serverFn(config, handler).`);
117
+ }
118
+ function isFunctionNode(node) {
119
+ return (node?.type === 'ArrowFunctionExpression' ||
120
+ node?.type === 'FunctionExpression');
121
+ }
122
+ function isStringLiteral(node) {
123
+ return node?.type === 'Literal' && typeof node.value === 'string';
124
+ }
125
+ /** Every `serverFn(...)` call anywhere in the module, not just exported ones. */
126
+ function countServerFnCalls(node, names) {
127
+ if (!node || typeof node !== 'object') {
128
+ return 0;
129
+ }
130
+ if (Array.isArray(node)) {
131
+ return node.reduce((total, child) => total + countServerFnCalls(child, names), 0);
132
+ }
133
+ const record = node;
134
+ let count = 0;
135
+ if (record.type === 'CallExpression') {
136
+ const callee = record['callee'];
137
+ if (callee?.type === 'Identifier' &&
138
+ callee.name &&
139
+ names.has(callee.name)) {
140
+ count += 1;
141
+ }
142
+ }
143
+ for (const key of Object.keys(record)) {
144
+ count += countServerFnCalls(record[key], names);
145
+ }
146
+ return count;
147
+ }
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLWZuLWNsaWVudC10cmFuc2Zvcm0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9wbGF0Zm9ybS9zcmMvbGliL3NlcnZlci1mbi1jbGllbnQtdHJhbnNmb3JtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDdkMsNEVBQTRFO0FBQzVFLHNEQUFzRDtBQUN0RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQTZCNUUsTUFBTSxnQkFBZ0IsR0FBRyx5QkFBeUIsQ0FBQztBQUVuRCxNQUFNLFVBQVUsbUJBQW1CLENBQ2pDLElBQVksRUFDWixNQUFNLEdBQUcsU0FBUztJQUVsQixxRUFBcUU7SUFDckUsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvQixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM1QyxNQUFNLElBQUksR0FBSSxPQUEyQixDQUFDLElBQUksQ0FBQztJQUUvQyxNQUFNLGtCQUFrQixHQUFHLHlCQUF5QixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FDaEMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssMEJBQTBCLENBQ25ELENBQUM7SUFFRixNQUFNLE9BQU8sR0FBb0IsRUFBRSxDQUFDO0lBQ3BDLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUM7UUFDeEIsSUFDRSxJQUFJLENBQUMsSUFBSSxLQUFLLHdCQUF3QjtZQUN0QyxJQUFJLENBQUMsV0FBVyxFQUFFLElBQUksS0FBSyxxQkFBcUIsRUFDaEQs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