Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/sharp-pears-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@astrojs/cloudflare': minor
---

Add support for Preview deployments (currently in private beta)

Non-inheritable bindings set internally by the Cloudflare adapter are now also set in the `previews` section of the config so that they are inherited by Preview deployments.
4 changes: 2 additions & 2 deletions packages/integrations/cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@
"dependencies": {
"@astrojs/internal-helpers": "workspace:*",
"@astrojs/underscore-redirects": "workspace:*",
"@cloudflare/vite-plugin": "^1.25.6",
"@cloudflare/vite-plugin": "^1.32.3",
"piccolore": "^0.1.3",
"tinyglobby": "^0.2.15",
"vite": "^7.3.1"
},
"peerDependencies": {
"astro": "^6.0.0",
"wrangler": "^4.61.1"
"wrangler": "^4.83.0"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20260228.0",
Expand Down
46 changes: 28 additions & 18 deletions packages/integrations/cloudflare/src/wrangler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,43 @@ export function cloudflareConfigCustomizer(
: (options?.imagesBindingName ?? DEFAULT_IMAGES_BINDING_NAME);

const customizer = (config: Partial<WorkerConfig>): Partial<WorkerConfig> => {
const hasSessionBinding = config.kv_namespaces?.some(
(kv) => kv.binding === sessionKVBindingName,
);
const hasImagesBinding = config.images?.binding !== undefined;
const getNonInheritableBindings = (
nonInheritableConfig: WorkerConfig['previews'],
): WorkerConfig['previews'] => {
const hasSessionBinding = nonInheritableConfig?.kv_namespaces?.some(
(kv) => kv.binding === sessionKVBindingName,
);
const hasImagesBinding = nonInheritableConfig?.images?.binding !== undefined;

return {
kv_namespaces:
!needsSessionKVBinding || hasSessionBinding
? undefined
: [
{
binding: sessionKVBindingName,
},
],
images:
hasImagesBinding || !imagesBindingName
? undefined
: {
binding: imagesBindingName,
},
};
};

const hasAssetsBinding = config.assets?.binding !== undefined;

return {
...getNonInheritableBindings(config),
main: config.main ?? '@astrojs/cloudflare/entrypoints/server',
kv_namespaces:
!needsSessionKVBinding || hasSessionBinding
? undefined
: [
{
binding: sessionKVBindingName,
},
],
images:
hasImagesBinding || !imagesBindingName
? undefined
: {
binding: imagesBindingName,
},
assets: hasAssetsBinding
? undefined
: {
binding: DEFAULT_ASSETS_BINDING_NAME,
},
previews: getNonInheritableBindings(config.previews),
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"astro": "workspace:*"
},
"devDependencies": {
"wrangler": "^4.69.0"
"wrangler": "^4.83.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"astro": "workspace:*"
},
"devDependencies": {
"wrangler": "^4.69.0"
"wrangler": "^4.83.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"dependencies": {
"@astrojs/cloudflare": "workspace:*",
"astro": "workspace:*",
"wrangler": "^4.69.0"
"wrangler": "^4.83.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"@astrojs/cloudflare": "workspace:*"
},
"devDependencies": {
"wrangler": "^4.69.0"
"wrangler": "^4.83.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"devDependencies": {
"astro": "workspace:*",
"wrangler": "^4.69.0"
"wrangler": "^4.83.0"
},
"scripts": {
"build": "astro build",
Expand Down
78 changes: 78 additions & 0 deletions packages/integrations/cloudflare/test/wrangler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,84 @@ describe('cloudflareConfigCustomizer', () => {
});
});

describe('previews', () => {
it('adds default bindings to previews when none exist', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({});

assert.deepEqual(result.previews?.kv_namespaces, [
{ binding: DEFAULT_SESSION_KV_BINDING_NAME },
]);
assert.deepEqual(result.previews?.images, { binding: DEFAULT_IMAGES_BINDING_NAME });
});

it('does not add SESSION binding to previews when one exists in previews config', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({
previews: {
kv_namespaces: [{ binding: DEFAULT_SESSION_KV_BINDING_NAME, id: 'preview-id' }],
},
});

assert.equal(result.previews?.kv_namespaces, undefined);
});

it('does not add IMAGES binding to previews when one exists in previews config', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({
previews: {
images: { binding: 'PREVIEW_IMAGES' },
},
});

assert.equal(result.previews?.images, undefined);
});

it('adds SESSION binding to previews even when top-level has it', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({
kv_namespaces: [{ binding: DEFAULT_SESSION_KV_BINDING_NAME, id: 'top-level-id' }],
});

// Top-level should not add (already exists)
assert.equal(result.kv_namespaces, undefined);
// Previews should add (not defined in previews config)
assert.deepEqual(result.previews?.kv_namespaces, [
{ binding: DEFAULT_SESSION_KV_BINDING_NAME },
]);
});

it('adds IMAGES binding to previews even when top-level has it', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({
images: { binding: 'TOP_LEVEL_IMAGES' },
});

// Top-level should not add (already exists)
assert.equal(result.images, undefined);
// Previews should add (not defined in previews config)
assert.deepEqual(result.previews?.images, { binding: DEFAULT_IMAGES_BINDING_NAME });
});

it('checks previews config independently from top-level config', () => {
const customizer = cloudflareConfigCustomizer();
const result = customizer({
kv_namespaces: [{ binding: DEFAULT_SESSION_KV_BINDING_NAME, id: 'top-level-id' }],
images: { binding: 'TOP_LEVEL_IMAGES' },
previews: {
kv_namespaces: [{ binding: DEFAULT_SESSION_KV_BINDING_NAME, id: 'preview-id' }],
images: { binding: 'PREVIEW_IMAGES' },
},
});

// Neither top-level nor previews should add bindings
assert.equal(result.kv_namespaces, undefined);
assert.equal(result.images, undefined);
assert.equal(result.previews?.kv_namespaces, undefined);
assert.equal(result.previews?.images, undefined);
});
});

describe('default binding names', () => {
it('exports DEFAULT_SESSION_KV_BINDING_NAME as SESSION', () => {
assert.equal(DEFAULT_SESSION_KV_BINDING_NAME, 'SESSION');
Expand Down
Loading
Loading