@ruvyxa/adapter-netlify 1.1.3 → 1.1.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAgD,MAAM,cAAc,CAAA;AAczF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAiND;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAsJpE;eAEc,OAAO"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAgD,MAAM,cAAc,CAAA;AAgBzF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AA8ND;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CA8JpE;eAEc,OAAO"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { CLIENT_BUNDLE_PREFIX, clientBuildOutput, DEFAULT_SECURITY_HEADERS, IMMUTABLE_CACHE_CONTROL, nonPublishableStrategies, projectRelativeOutDir, PUBLIC_ASSET_CACHE_CONTROL, publicAssetGlobs, runtimeBuildPolicy, validateBuildContext, } from '@ruvyxa/core';
2
+ import { CLIENT_BUNDLE_PREFIX, clientBuildOutput, documentCacheOptionsSource, isrTemporaryCacheSource, DEFAULT_SECURITY_HEADERS, IMMUTABLE_CACHE_CONTROL, nonPublishableStrategies, projectRelativeOutDir, PUBLIC_ASSET_CACHE_CONTROL, publicAssetGlobs, runtimeBuildPolicy, validateBuildContext, } from '@ruvyxa/core';
3
3
  /**
4
4
  * Netlify Functions v2 handler source code.
5
5
  *
@@ -7,9 +7,9 @@ import { CLIENT_BUNDLE_PREFIX, clientBuildOutput, DEFAULT_SECURITY_HEADERS, IMMU
7
7
  * handler using the Web-standard Request/Response API. Reads the route
8
8
  * manifest and handles SSR/API/ISR/PPR requests.
9
9
  */
10
- function netlifyHandlerSource(runtimePolicy, functionConfig) {
10
+ function netlifyHandlerSource(runtimePolicy, functionConfig, buildId) {
11
11
  return `import { createHandler, prerenderRelativePath } from './serverless-handler.mjs';
12
- import { applyPluginHttp, loadActionModule, loadRouteModule } from './route-modules.mjs';
12
+ import { applyPluginHttp, documentCacheHandler, loadActionModule, loadRouteModule } from './route-modules.mjs';
13
13
  // Netlify bundles the function with esbuild, so anything the deployed code
14
14
  // needs must be reachable through the module graph. A sibling manifest.json
15
15
  // read from import.meta.dirname is not, and never reaches /var/task.
@@ -27,10 +27,7 @@ const runtimePolicy = ${JSON.stringify(runtimePolicy ?? {})};
27
27
  // serves SSG pages from the publish directory before the function is ever
28
28
  // invoked (config.preferStatic).
29
29
  const prerenderDir = path.join(import.meta.dirname, 'prerender');
30
- // The function bundle directory is read-only at runtime; only the platform
31
- // tmp directory accepts writes. ISR revalidations land there and are read
32
- // back before the bundled deploy-time prerender output.
33
- const isrCacheDir = path.join(os.tmpdir(), 'ruvyxa-isr-cache');
30
+ ${isrTemporaryCacheSource(buildId)}
34
31
 
35
32
  /**
36
33
  * The cache tag a document is stored under, so one path can be dropped from
@@ -73,6 +70,35 @@ const readEntry = (htmlPath, revalidate) => {
73
70
  return { html, stale };
74
71
  };
75
72
 
73
+ // Named rather than passed inline, so a project that declares \`cache.handler\`
74
+ // can stand its own store in front of these. See \`documentCacheOptionsSource\`
75
+ // in \`@ruvyxa/core\`; the registry supplies \`documentCacheHandler\`.
76
+ const platformReadPrerendered = (pathname, revalidate = 60) => {
77
+ // prerenderRelativePath rejects any request path that cannot be mapped to a
78
+ // location inside the cache directories, so reads can never escape them.
79
+ const relative = prerenderRelativePath(pathname);
80
+ if (relative === null) return null;
81
+ try {
82
+ return readEntry(path.join(isrCacheDir, relative), revalidate);
83
+ } catch {
84
+ // fall through to the bundled prerender output
85
+ }
86
+ try {
87
+ return readEntry(path.join(prerenderDir, relative), revalidate);
88
+ } catch {
89
+ return null;
90
+ }
91
+ };
92
+
93
+ const platformWritePrerendered = (pathname, html, revalidate, forced) => {
94
+ const relative = prerenderRelativePath(pathname);
95
+ if (relative === null) return;
96
+ const htmlPath = path.join(isrCacheDir, relative);
97
+ mkdirSync(path.dirname(htmlPath), { recursive: true });
98
+ writeFileSync(htmlPath, html, 'utf8');
99
+ if (forced === true) return purgeDurableCache(pathname);
100
+ };
101
+
76
102
  const handler = createHandler({
77
103
  routes: manifest.routes,
78
104
  middleware: runtimePolicy.middleware,
@@ -82,35 +108,21 @@ const handler = createHandler({
82
108
  importAction: loadActionModule,
83
109
  pluginHttp: applyPluginHttp,
84
110
  security: runtimePolicy.security,
85
- readPrerendered: (pathname, revalidate = 60) => {
86
- // prerenderRelativePath rejects any request path that cannot be mapped to a
87
- // location inside the cache directories, so reads can never escape them.
88
- const relative = prerenderRelativePath(pathname);
89
- if (relative === null) return null;
90
- try {
91
- return readEntry(path.join(isrCacheDir, relative), revalidate);
92
- } catch {
93
- // fall through to the bundled prerender output
94
- }
95
- try {
96
- return readEntry(path.join(prerenderDir, relative), revalidate);
97
- } catch {
98
- return null;
99
- }
100
- },
101
- writePrerendered: (pathname, html, revalidate, forced) => {
102
- const relative = prerenderRelativePath(pathname);
103
- if (relative === null) return;
104
- const htmlPath = path.join(isrCacheDir, relative);
105
- mkdirSync(path.dirname(htmlPath), { recursive: true });
106
- writeFileSync(htmlPath, html, 'utf8');
107
- if (forced === true) return purgeDurableCache(pathname);
108
- },
111
+ ${documentCacheOptionsSource('platformReadPrerendered', 'platformWritePrerendered')}
109
112
  // The project's own not-found page, pre-rendered by the build and carried
110
113
  // inline in the manifest: an unmatched URL is answered with the page the
111
114
  // application actually wrote, on every host.
112
115
  notFoundDocument: manifest.notFoundDocument,
113
116
  supportedStrategies: ['ssr', 'ssg', 'csr', 'isr', 'ppr', 'api'],
117
+ // Netlify's own edge writes \`X-Nf-Client-Connection-IP\` and overwrites any
118
+ // inbound copy of it, so on this platform the header *is* the client.
119
+ // Declared here rather than assumed by the handler: the same handler runs on
120
+ // a self-hosted server where nothing writes it. Without a declaration
121
+ // identity fell through to a right-to-left scan of \`X-Forwarded-For\`, whose
122
+ // rightmost entry here is a fixed platform address — so the built-in \`rate\`
123
+ // middleware, the server-action rate limiter, and the replay quota all
124
+ // counted every visitor into one bucket.
125
+ clientIpHeaders: ['x-nf-client-connection-ip'],
114
126
  });
115
127
 
116
128
  // Netlify Functions v2 — Web-standard Request/Response
@@ -272,7 +284,7 @@ export function netlify(options = {}) {
272
284
  {
273
285
  kind: 'function',
274
286
  path: 'deploy/netlify/functions/ruvyxa-handler',
275
- handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor()),
287
+ handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor(), ctx.deployManifest?.buildId ?? ''),
276
288
  },
277
289
  // Netlify config for the deploy directory
278
290
  {
@@ -289,7 +301,7 @@ export function netlify(options = {}) {
289
301
  kind: 'function',
290
302
  path: '.netlify/v1/functions/ruvyxa-handler',
291
303
  scope: 'project',
292
- handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor()),
304
+ handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor(), ctx.deployManifest?.buildId ?? ''),
293
305
  },
294
306
  {
295
307
  kind: 'file',
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruvyxa/adapter-netlify",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "Shape Ruvyxa builds for Netlify functions and assets with a small typed adapter contract.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -56,7 +56,7 @@
56
56
  }
57
57
  },
58
58
  "dependencies": {
59
- "@ruvyxa/core": "^1.1.3"
59
+ "@ruvyxa/core": "^1.1.4"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/node": "24.13.3"
package/src/index.ts CHANGED
@@ -4,6 +4,8 @@ import type { Adapter, AdapterArtifact, AdapterOutput, BuildContext } from '@ruv
4
4
  import {
5
5
  CLIENT_BUNDLE_PREFIX,
6
6
  clientBuildOutput,
7
+ documentCacheOptionsSource,
8
+ isrTemporaryCacheSource,
7
9
  DEFAULT_SECURITY_HEADERS,
8
10
  IMMUTABLE_CACHE_CONTROL,
9
11
  nonPublishableStrategies,
@@ -64,9 +66,10 @@ export interface NetlifyAdapterOptions {
64
66
  function netlifyHandlerSource(
65
67
  runtimePolicy: unknown,
66
68
  functionConfig: NetlifyFunctionConfig,
69
+ buildId: string,
67
70
  ): string {
68
71
  return `import { createHandler, prerenderRelativePath } from './serverless-handler.mjs';
69
- import { applyPluginHttp, loadActionModule, loadRouteModule } from './route-modules.mjs';
72
+ import { applyPluginHttp, documentCacheHandler, loadActionModule, loadRouteModule } from './route-modules.mjs';
70
73
  // Netlify bundles the function with esbuild, so anything the deployed code
71
74
  // needs must be reachable through the module graph. A sibling manifest.json
72
75
  // read from import.meta.dirname is not, and never reaches /var/task.
@@ -84,10 +87,7 @@ const runtimePolicy = ${JSON.stringify(runtimePolicy ?? {})};
84
87
  // serves SSG pages from the publish directory before the function is ever
85
88
  // invoked (config.preferStatic).
86
89
  const prerenderDir = path.join(import.meta.dirname, 'prerender');
87
- // The function bundle directory is read-only at runtime; only the platform
88
- // tmp directory accepts writes. ISR revalidations land there and are read
89
- // back before the bundled deploy-time prerender output.
90
- const isrCacheDir = path.join(os.tmpdir(), 'ruvyxa-isr-cache');
90
+ ${isrTemporaryCacheSource(buildId)}
91
91
 
92
92
  /**
93
93
  * The cache tag a document is stored under, so one path can be dropped from
@@ -130,6 +130,35 @@ const readEntry = (htmlPath, revalidate) => {
130
130
  return { html, stale };
131
131
  };
132
132
 
133
+ // Named rather than passed inline, so a project that declares \`cache.handler\`
134
+ // can stand its own store in front of these. See \`documentCacheOptionsSource\`
135
+ // in \`@ruvyxa/core\`; the registry supplies \`documentCacheHandler\`.
136
+ const platformReadPrerendered = (pathname, revalidate = 60) => {
137
+ // prerenderRelativePath rejects any request path that cannot be mapped to a
138
+ // location inside the cache directories, so reads can never escape them.
139
+ const relative = prerenderRelativePath(pathname);
140
+ if (relative === null) return null;
141
+ try {
142
+ return readEntry(path.join(isrCacheDir, relative), revalidate);
143
+ } catch {
144
+ // fall through to the bundled prerender output
145
+ }
146
+ try {
147
+ return readEntry(path.join(prerenderDir, relative), revalidate);
148
+ } catch {
149
+ return null;
150
+ }
151
+ };
152
+
153
+ const platformWritePrerendered = (pathname, html, revalidate, forced) => {
154
+ const relative = prerenderRelativePath(pathname);
155
+ if (relative === null) return;
156
+ const htmlPath = path.join(isrCacheDir, relative);
157
+ mkdirSync(path.dirname(htmlPath), { recursive: true });
158
+ writeFileSync(htmlPath, html, 'utf8');
159
+ if (forced === true) return purgeDurableCache(pathname);
160
+ };
161
+
133
162
  const handler = createHandler({
134
163
  routes: manifest.routes,
135
164
  middleware: runtimePolicy.middleware,
@@ -139,35 +168,21 @@ const handler = createHandler({
139
168
  importAction: loadActionModule,
140
169
  pluginHttp: applyPluginHttp,
141
170
  security: runtimePolicy.security,
142
- readPrerendered: (pathname, revalidate = 60) => {
143
- // prerenderRelativePath rejects any request path that cannot be mapped to a
144
- // location inside the cache directories, so reads can never escape them.
145
- const relative = prerenderRelativePath(pathname);
146
- if (relative === null) return null;
147
- try {
148
- return readEntry(path.join(isrCacheDir, relative), revalidate);
149
- } catch {
150
- // fall through to the bundled prerender output
151
- }
152
- try {
153
- return readEntry(path.join(prerenderDir, relative), revalidate);
154
- } catch {
155
- return null;
156
- }
157
- },
158
- writePrerendered: (pathname, html, revalidate, forced) => {
159
- const relative = prerenderRelativePath(pathname);
160
- if (relative === null) return;
161
- const htmlPath = path.join(isrCacheDir, relative);
162
- mkdirSync(path.dirname(htmlPath), { recursive: true });
163
- writeFileSync(htmlPath, html, 'utf8');
164
- if (forced === true) return purgeDurableCache(pathname);
165
- },
171
+ ${documentCacheOptionsSource('platformReadPrerendered', 'platformWritePrerendered')}
166
172
  // The project's own not-found page, pre-rendered by the build and carried
167
173
  // inline in the manifest: an unmatched URL is answered with the page the
168
174
  // application actually wrote, on every host.
169
175
  notFoundDocument: manifest.notFoundDocument,
170
176
  supportedStrategies: ['ssr', 'ssg', 'csr', 'isr', 'ppr', 'api'],
177
+ // Netlify's own edge writes \`X-Nf-Client-Connection-IP\` and overwrites any
178
+ // inbound copy of it, so on this platform the header *is* the client.
179
+ // Declared here rather than assumed by the handler: the same handler runs on
180
+ // a self-hosted server where nothing writes it. Without a declaration
181
+ // identity fell through to a right-to-left scan of \`X-Forwarded-For\`, whose
182
+ // rightmost entry here is a fixed platform address — so the built-in \`rate\`
183
+ // middleware, the server-action rate limiter, and the replay quota all
184
+ // counted every visitor into one bucket.
185
+ clientIpHeaders: ['x-nf-client-connection-ip'],
171
186
  });
172
187
 
173
188
  // Netlify Functions v2 — Web-standard Request/Response
@@ -386,7 +401,11 @@ export function netlify(options: NetlifyAdapterOptions = {}): Adapter {
386
401
  {
387
402
  kind: 'function',
388
403
  path: 'deploy/netlify/functions/ruvyxa-handler',
389
- handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor()),
404
+ handlerSource: netlifyHandlerSource(
405
+ runtimePolicy,
406
+ functionConfigFor(),
407
+ ctx.deployManifest?.buildId ?? '',
408
+ ),
390
409
  },
391
410
  // Netlify config for the deploy directory
392
411
  {
@@ -403,7 +422,11 @@ export function netlify(options: NetlifyAdapterOptions = {}): Adapter {
403
422
  kind: 'function',
404
423
  path: '.netlify/v1/functions/ruvyxa-handler',
405
424
  scope: 'project',
406
- handlerSource: netlifyHandlerSource(runtimePolicy, functionConfigFor()),
425
+ handlerSource: netlifyHandlerSource(
426
+ runtimePolicy,
427
+ functionConfigFor(),
428
+ ctx.deployManifest?.buildId ?? '',
429
+ ),
407
430
  } satisfies AdapterArtifact,
408
431
  {
409
432
  kind: 'file',