@ruvyxa/adapter-cloudflare 1.0.19 → 1.0.21

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/dist/index.d.ts CHANGED
@@ -17,8 +17,13 @@ export interface CloudflareAdapterOptions {
17
17
  */
18
18
  projectConfig?: boolean;
19
19
  /**
20
- * Cloudflare Workers compatibility date. This determines which runtime
21
- * APIs are available. Defaults to the current date at build time.
20
+ * Cloudflare Workers compatibility date, which pins the runtime API
21
+ * behavior the Worker was written against.
22
+ *
23
+ * Defaults to a fixed date this adapter is tested with, never the current
24
+ * date: a build-time date makes two builds of the same commit differ, and a
25
+ * date newer than the workerd version on the deploy machine is rejected by
26
+ * `wrangler`. Raise it deliberately after checking Cloudflare's changelog.
22
27
  */
23
28
  compatibilityDate?: string;
24
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgD,MAAM,cAAc,CAAA;AAGzF;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAqCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CA8FjF;eAEc,iBAAiB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgD,MAAM,cAAc,CAAA;AAQzF;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAgDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CA+FjF;eAEc,iBAAiB"}
package/dist/index.js CHANGED
@@ -1,4 +1,10 @@
1
- import { clientBuildOutput, projectRelativeOutDir, validateBuildContext } from '@ruvyxa/core';
1
+ import { clientBuildOutput, headersFileContents, projectRelativeOutDir, validateBuildContext, } from '@ruvyxa/core';
2
+ /**
3
+ * Compatibility date this adapter's generated Worker is verified against.
4
+ *
5
+ * Bump only together with a check of the Workers runtime changes it opts into.
6
+ */
7
+ const DEFAULT_COMPATIBILITY_DATE = '2025-09-01';
2
8
  /**
3
9
  * Worker fetch handler source code.
4
10
  *
@@ -12,7 +18,9 @@ import { clientBuildOutput, projectRelativeOutDir, validateBuildContext } from '
12
18
  function workerHandlerSource() {
13
19
  return `import { createHandler } from './serverless-handler.mjs';
14
20
  import { loadRouteModule } from './route-modules.mjs';
15
- import manifest from './manifest.json';
21
+ // A JS module, not a JSON import: import attributes for JSON are not uniformly
22
+ // available across bundlers and Worker compatibility dates.
23
+ import manifest from './manifest.mjs';
16
24
 
17
25
  const handler = createHandler({
18
26
  routes: manifest.routes,
@@ -28,7 +36,9 @@ const handler = createHandler({
28
36
 
29
37
  export default {
30
38
  async fetch(request, env, ctx) {
31
- return handler(request);
39
+ // The runtime context carries waitUntil, which the shared handler uses to
40
+ // finish background work after the response is returned.
41
+ return handler(request, ctx);
32
42
  },
33
43
  };
34
44
  `;
@@ -64,7 +74,7 @@ export function cloudflareAdapter(options = {}) {
64
74
  supports: ['ssr', 'ssg', 'csr', 'api'],
65
75
  build(ctx) {
66
76
  validateBuildContext(ctx, 'cloudflareAdapter');
67
- const compatDate = options.compatibilityDate ?? new Date().toISOString().slice(0, 10);
77
+ const compatDate = options.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE;
68
78
  // Config files are committed or read on other machines; never embed the
69
79
  // absolute build-machine outDir in them.
70
80
  const relativeOutDir = projectRelativeOutDir(ctx);
@@ -107,12 +117,13 @@ export function cloudflareAdapter(options = {}) {
107
117
  contents: wranglerConfig + '\n',
108
118
  },
109
119
  {
110
- // Workers static assets read _headers from the asset directory;
111
- // hashed client bundles live under /__ruvyxa/client/ and are
112
- // immutable.
120
+ // Workers static assets read _headers from the asset directory.
121
+ // Hashed client bundles are immutable; `public/` assets otherwise
122
+ // inherit Cloudflare's `max-age=0, must-revalidate` default, which
123
+ // re-fetches every image and font on each navigation.
113
124
  kind: 'file',
114
125
  path: 'deploy/cloudflare/assets/_headers',
115
- contents: '/__ruvyxa/client/*\n Cache-Control: public, max-age=31536000, immutable\n',
126
+ contents: headersFileContents(),
116
127
  },
117
128
  ...(options.projectConfig === true
118
129
  ? [
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-cloudflare",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "Shape Ruvyxa builds for Cloudflare edge targets with typed worker and asset output metadata.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -8,6 +8,7 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
10
  "dist",
11
+ "src",
11
12
  "README.md"
12
13
  ],
13
14
  "keywords": [
@@ -26,7 +27,7 @@
26
27
  },
27
28
  "homepage": "https://github.com/thirawat27/ruvyxa#readme",
28
29
  "engines": {
29
- "node": ">=22.0.0"
30
+ "node": ">=22.12.0"
30
31
  },
31
32
  "publishConfig": {
32
33
  "access": "public"
@@ -38,7 +39,7 @@
38
39
  }
39
40
  },
40
41
  "dependencies": {
41
- "@ruvyxa/core": "^1.0.19"
42
+ "@ruvyxa/core": "^1.0.21"
42
43
  },
43
44
  "scripts": {
44
45
  "build": "tsc -p tsconfig.json",
package/src/index.ts ADDED
@@ -0,0 +1,199 @@
1
+ import type { Adapter, AdapterArtifact, AdapterOutput, BuildContext } from '@ruvyxa/core'
2
+ import {
3
+ clientBuildOutput,
4
+ headersFileContents,
5
+ projectRelativeOutDir,
6
+ validateBuildContext,
7
+ } from '@ruvyxa/core'
8
+
9
+ /**
10
+ * Options for the Cloudflare Workers deployment adapter.
11
+ */
12
+ export interface CloudflareAdapterOptions {
13
+ /** Custom worker entry point path. Defaults to `${outDir}/server/app`. */
14
+ workerEntry?: string
15
+ /**
16
+ * Also emit a `wrangler.jsonc` at the project root pointing at the
17
+ * generated Worker script and static assets. An existing project
18
+ * `wrangler.jsonc` is never overwritten.
19
+ *
20
+ * Off by default: the deploy directory already contains a self-sufficient
21
+ * config, so `wrangler deploy -c .ruvyxa/deploy/cloudflare/wrangler.jsonc`
22
+ * works with no file at the project root.
23
+ * @default false
24
+ */
25
+ projectConfig?: boolean
26
+ /**
27
+ * Cloudflare Workers compatibility date, which pins the runtime API
28
+ * behavior the Worker was written against.
29
+ *
30
+ * Defaults to a fixed date this adapter is tested with, never the current
31
+ * date: a build-time date makes two builds of the same commit differ, and a
32
+ * date newer than the workerd version on the deploy machine is rejected by
33
+ * `wrangler`. Raise it deliberately after checking Cloudflare's changelog.
34
+ */
35
+ compatibilityDate?: string
36
+ }
37
+
38
+ /**
39
+ * Compatibility date this adapter's generated Worker is verified against.
40
+ *
41
+ * Bump only together with a check of the Workers runtime changes it opts into.
42
+ */
43
+ const DEFAULT_COMPATIBILITY_DATE = '2025-09-01'
44
+
45
+ /**
46
+ * Worker fetch handler source code.
47
+ *
48
+ * This is the platform-specific entry that wraps the generic Ruvyxa serverless
49
+ * handler into a Cloudflare Workers `fetch` event handler. It reads the route
50
+ * manifest and delegates to the serverless handler for SSR/API/ISR/PPR.
51
+ *
52
+ * Static assets (client bundles, pre-rendered pages for SSG/CSR) are served
53
+ * by Cloudflare's `assets` binding; the Worker only handles dynamic routes.
54
+ */
55
+ function workerHandlerSource(): string {
56
+ return `import { createHandler } from './serverless-handler.mjs';
57
+ import { loadRouteModule } from './route-modules.mjs';
58
+ // A JS module, not a JSON import: import attributes for JSON are not uniformly
59
+ // available across bundlers and Worker compatibility dates.
60
+ import manifest from './manifest.mjs';
61
+
62
+ const handler = createHandler({
63
+ routes: manifest.routes,
64
+ importPage: loadRouteModule,
65
+ importApi: loadRouteModule,
66
+ readPrerendered: (pathname) => {
67
+ // In Workers, pre-rendered pages are served as static assets.
68
+ // ISR revalidation requires KV or Durable Objects (not yet supported).
69
+ return null;
70
+ },
71
+ supportedStrategies: ['ssr', 'ssg', 'csr', 'api'],
72
+ });
73
+
74
+ export default {
75
+ async fetch(request, env, ctx) {
76
+ // The runtime context carries waitUntil, which the shared handler uses to
77
+ // finish background work after the response is returned.
78
+ return handler(request, ctx);
79
+ },
80
+ };
81
+ `
82
+ }
83
+
84
+ /**
85
+ * Create a Cloudflare Workers deployment adapter for Ruvyxa.
86
+ *
87
+ * Produces a Worker fetch handler and static assets for deployment via
88
+ * `wrangler`. Supports SSR, API routes, SSG, and CSR. ISR and PPR are
89
+ * rejected with RUV2210 because they require persistent storage (KV/DO)
90
+ * which is not yet integrated.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { config } from "ruvyxa/config"
95
+ * import { cloudflareAdapter } from "@ruvyxa/adapter-cloudflare"
96
+ *
97
+ * export default config({
98
+ * adapter: cloudflareAdapter()
99
+ * })
100
+ * ```
101
+ */
102
+ export function cloudflareAdapter(options: CloudflareAdapterOptions = {}): Adapter {
103
+ if (options.workerEntry !== undefined && typeof options.workerEntry !== 'string') {
104
+ throw new Error(
105
+ `[RUV2001] cloudflareAdapter: "workerEntry" must be a string, got ${typeof options.workerEntry}`,
106
+ )
107
+ }
108
+
109
+ if (options.workerEntry !== undefined && options.workerEntry.trim() === '') {
110
+ throw new Error(`[RUV2001] cloudflareAdapter: "workerEntry" must not be an empty string`)
111
+ }
112
+
113
+ return {
114
+ name: 'cloudflare',
115
+ target: 'edge',
116
+ supports: ['ssr', 'ssg', 'csr', 'api'],
117
+ build(ctx: BuildContext): AdapterOutput {
118
+ validateBuildContext(ctx, 'cloudflareAdapter')
119
+
120
+ const compatDate = options.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE
121
+ // Config files are committed or read on other machines; never embed the
122
+ // absolute build-machine outDir in them.
123
+ const relativeOutDir = projectRelativeOutDir(ctx)
124
+
125
+ const wranglerConfig = JSON.stringify(
126
+ {
127
+ name: 'ruvyxa-app',
128
+ main: './worker/index.mjs',
129
+ compatibility_date: compatDate,
130
+ assets: { directory: './assets' },
131
+ },
132
+ null,
133
+ 2,
134
+ )
135
+
136
+ const projectWranglerConfig = JSON.stringify(
137
+ {
138
+ name: 'ruvyxa-app',
139
+ main: `${relativeOutDir}/deploy/cloudflare/worker/index.mjs`,
140
+ compatibility_date: compatDate,
141
+ assets: { directory: `${relativeOutDir}/deploy/cloudflare/assets` },
142
+ },
143
+ null,
144
+ 2,
145
+ )
146
+
147
+ return {
148
+ name: 'cloudflare',
149
+ target: 'edge',
150
+ platform: 'cloudflare',
151
+ entry: options.workerEntry ?? `${ctx.outDir}/server/app`,
152
+ assetsDir: `${ctx.outDir}/assets`,
153
+ ...clientBuildOutput(ctx),
154
+ configFiles: ['wrangler.jsonc'],
155
+ artifacts: [
156
+ // Static assets served by Cloudflare's asset binding. `optional`:
157
+ // an API-only or all-SSR app has no prerendered pages; the Worker
158
+ // still serves every route, so the missing prerender directory must
159
+ // not fail the build.
160
+ { kind: 'static-site', path: 'deploy/cloudflare/assets', optional: true },
161
+ // Worker function bundle (SSR/API handler)
162
+ {
163
+ kind: 'function',
164
+ path: 'deploy/cloudflare/worker',
165
+ handlerSource: workerHandlerSource(),
166
+ },
167
+ // Wrangler config pointing at the Worker + assets
168
+ {
169
+ kind: 'file',
170
+ path: 'deploy/cloudflare/wrangler.jsonc',
171
+ contents: wranglerConfig + '\n',
172
+ },
173
+ {
174
+ // Workers static assets read _headers from the asset directory.
175
+ // Hashed client bundles are immutable; `public/` assets otherwise
176
+ // inherit Cloudflare's `max-age=0, must-revalidate` default, which
177
+ // re-fetches every image and font on each navigation.
178
+ kind: 'file',
179
+ path: 'deploy/cloudflare/assets/_headers',
180
+ contents: headersFileContents(),
181
+ },
182
+ ...(options.projectConfig === true
183
+ ? [
184
+ {
185
+ kind: 'file',
186
+ path: 'wrangler.jsonc',
187
+ scope: 'project',
188
+ skipIfExists: true,
189
+ contents: projectWranglerConfig + '\n',
190
+ } satisfies AdapterArtifact,
191
+ ]
192
+ : []),
193
+ ],
194
+ }
195
+ },
196
+ }
197
+ }
198
+
199
+ export default cloudflareAdapter