-
Notifications
You must be signed in to change notification settings - Fork 674
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(workers-shared): Add Asset Server Worker behaviour (#6539)
* feat(workers-shared): Add Assets Server Worker behaviour This PR adds a proper-ish implementation of a very un-opinionated Asset Worker. Proper-ish because it handles the essential things needed for AW to work, but we expect some other details we'll be needed as Workers + Assets work progresses further. As part of this basic behaviour, we are covering: - headers handling - `200`/`404`/`500` response handling - fetching data from KV
- Loading branch information
1 parent
419e9f0
commit 6c057d1
Showing
22 changed files
with
849 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
--- | ||
"@cloudflare/workers-shared": minor | ||
--- | ||
|
||
feat: Add basic Asset Worker behaviour | ||
|
||
This commit implements a basic Asset Worker behaviour, including: | ||
|
||
- headers handling | ||
- `200`/`404`/`500` response handling | ||
- fetching data from KV |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Workers with Assets | ||
|
||
Welcome to Workers + Assets YAY! | ||
|
||
Please proceed with much excitement ^.^ | ||
|
||
................. | ||
.......-++**********:. | ||
..-+****++**********#: | ||
...-+***+++====+********##= | ||
....:=****+======+***********##+ | ||
....-****+======+*************###+ | ||
.:==+*+======+***************####= | ||
....-===--=====++****************#####: | ||
....:====-:::-==+******************#####+. | ||
..-====:::::::+*******************#####*.. | ||
..-===-:::::::-==+*****************######=.. | ||
..-===-::::::-=======***************######*. | ||
...-===-::::::-==========+************######*:. | ||
...-===-::::::-==----========+*********#######:.. | ||
.-===-::::::--::::::::::-======+******#######-. . | ||
..:====::::::-=:::-*####*-:::-=======+**#######-. | ||
.:====-:::::-==:::*#########-::========+**#####- | ||
..====-:::::-===-::###########*:::======*******+.. | ||
..=+====:::::=====::-############:::====+*******=... | ||
....:=++====:::-======-::###########*:::===+*******-.. | ||
...........:-==+**+=++++=============-:::*#########-::===********:.. | ||
....--=+************====+++===============:::=*####*=:::-=+*******=.. | ||
.:*************###*=====++++================::::::::::-==********:.. | ||
..*****#############=======++++==========================+*******+... | ||
...+****#############*==:::-===++++========================********-. | ||
...+****###############+=::::=====+++++====================********+... | ||
.=****################*=-:::-======+++++=================+********:.. | ||
..-****##################===:-=========++++++=============+********:.. | ||
.+***####################===========+***#++++++=========+********=.. | ||
.*###################+-.-=======+****##*==+++++++====+********=... | ||
...-+#############*=...-++=====+****####+=====++++++*********+... | ||
....-*######+:.....++++===******####==========+*######**+.. | ||
...+=.....:::-+++++******#####=========+***######*.. | ||
.......::::::=++******#####+========***********:... | ||
....::::::...+*****######=======+**********##*. | ||
..:::::....-*****######+=====+**********#####*. | ||
...:::::...:******#####*+++++*********#########+. | ||
..:::::...+*****######+++++++=.=###############:. | ||
.:::::..-*****######-..-=++=..-##########***###.. | ||
....::::..=****######=....::::..:########******##*.. | ||
...::::..+***######-.....::::...*##***********###=.. | ||
..::::...-**####*:......::::...###************###-.. | ||
..:::......=##*:......:::::...+##*************###: | ||
...::::...............:::::....+##*************####. | ||
...::::::::::::::..:::::::......**************###-.. | ||
.::::::::::::::::::::::..... ...:***********###+.... | ||
..::::.......::::::...... ..:********###*:... | ||
........ ...=******###=.. | ||
.=***###+.. | ||
..*####:... | ||
........ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
.----------------. .----------------. .----------------. | ||
| .--------------. || .--------------. || .--------------. | | ||
| | ____ ____ | || | __ | || | ____ ____ | | | ||
| | |_ _||_ _| | || | / \ | || | |_ _||_ _| | | | ||
| | \ \ / / | || | / /\ \ | || | \ \ / / | | | ||
| | \ \/ / | || | / ____ \ | || | \ \/ / | | | ||
| | _| |_ | || | _/ / \ \_ | || | _| |_ | | | ||
| | |______| | || ||____| |____|| || | |______| | | | ||
| | | || | | || | | | | ||
| '--------------' || '--------------' || '--------------' | | ||
'----------------' '----------------' '----------------' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// have the browser check in with the server to make sure its local cache is valid before using it | ||
export const CACHE_CONTROL_BROWSER = "public, max-age=0, must-revalidate"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
type Env = { | ||
// ASSETS_MANIFEST is a pipeline binding to an ArrayBuffer containing the | ||
// binary-encoded site manifest | ||
ASSETS_MANIFEST: ArrayBuffer; | ||
|
||
// ASSETS_KV_NAMESPACE is a pipeline binding to the KV namespace that the | ||
// assets are in. | ||
ASSETS_KV_NAMESPACE: KVNamespace; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,62 @@ | ||
import { WorkerEntrypoint } from "cloudflare:workers"; | ||
import { AssetsManifest } from "./assets-manifest"; | ||
import { | ||
InternalServerErrorResponse, | ||
MethodNotAllowedResponse, | ||
NotFoundResponse, | ||
OkResponse, | ||
} from "./responses"; | ||
import { getAdditionalHeaders, getMergedHeaders } from "./utils/headers"; | ||
import { getAssetWithMetadataFromKV } from "./utils/kv"; | ||
|
||
interface Env { | ||
/** | ||
* ASSETS_MANIFEST is a pipeline binding to an ArrayBuffer containing the | ||
* binary-encoded site manifest | ||
*/ | ||
ASSETS_MANIFEST: ArrayBuffer; | ||
/** | ||
* ASSETS_KV_NAMESPACE is a pipeline binding to the KV namespace that the | ||
* assets are in. | ||
*/ | ||
ASSETS_KV_NAMESPACE: KVNamespace; | ||
} | ||
|
||
export default { | ||
async fetch(request: Request, env: Env) { | ||
const { ASSETS_MANIFEST, ASSETS_KV_NAMESPACE } = env; | ||
export default class extends WorkerEntrypoint<Env> { | ||
async fetch(request: Request) { | ||
if (request.method.toLowerCase() !== "get") { | ||
return new MethodNotAllowedResponse(); | ||
} | ||
|
||
const url = new URL(request.url); | ||
const { pathname } = url; | ||
try { | ||
return this.handleRequest(request); | ||
} catch (err) { | ||
return new InternalServerErrorResponse(err); | ||
} | ||
} | ||
|
||
const assetsManifest = new AssetsManifest(ASSETS_MANIFEST); | ||
const assetKey = await assetsManifest.get(pathname); | ||
if (!assetKey) { | ||
return new Response("Not Found", { status: 404 }); | ||
async handleRequest(request: Request) { | ||
const assetEntry = await this.getAssetEntry(request); | ||
if (!assetEntry) { | ||
return new NotFoundResponse(); | ||
} | ||
|
||
const content = await ASSETS_KV_NAMESPACE.get(assetKey); | ||
if (!content) { | ||
const assetResponse = await getAssetWithMetadataFromKV( | ||
this.env.ASSETS_KV_NAMESPACE, | ||
assetEntry | ||
); | ||
|
||
if (!assetResponse || !assetResponse.value) { | ||
throw new Error( | ||
`Requested asset ${assetKey} exists in the asset manifest but not in the KV namespace.` | ||
`Requested asset ${assetEntry} exists in the asset manifest but not in the KV namespace.` | ||
); | ||
} | ||
|
||
return new Response(content); | ||
}, | ||
}; | ||
const { value: assetContent, metadata: assetMetadata } = assetResponse; | ||
const additionalHeaders = getAdditionalHeaders( | ||
assetEntry, | ||
assetMetadata, | ||
request | ||
); | ||
const headers = getMergedHeaders(request.headers, additionalHeaders); | ||
|
||
return new OkResponse(assetContent, { headers }); | ||
} | ||
|
||
private async getAssetEntry(request: Request) { | ||
const url = new URL(request.url); | ||
let { pathname } = url; | ||
|
||
const assetsManifest = new AssetsManifest(this.env.ASSETS_MANIFEST); | ||
pathname = globalThis.decodeURIComponent(pathname); | ||
|
||
return await assetsManifest.get(pathname); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
packages/workers-shared/asset-server-worker/src/responses.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
export class OkResponse extends Response { | ||
constructor(body: BodyInit | null, init?: ResponseInit) { | ||
super(body, { | ||
...init, | ||
status: 200, | ||
}); | ||
} | ||
} | ||
|
||
export class NotFoundResponse extends Response { | ||
constructor(...[body, init]: ConstructorParameters<typeof Response>) { | ||
super(body, { | ||
...init, | ||
status: 404, | ||
statusText: "Not Found", | ||
}); | ||
} | ||
} | ||
|
||
export class MethodNotAllowedResponse extends Response { | ||
constructor(...[body, init]: ConstructorParameters<typeof Response>) { | ||
super(body, { | ||
...init, | ||
status: 405, | ||
statusText: "Method Not Allowed", | ||
}); | ||
} | ||
} | ||
|
||
export class InternalServerErrorResponse extends Response { | ||
constructor(err: Error, init?: ResponseInit) { | ||
super(undefined, { | ||
...init, | ||
status: 500, | ||
}); | ||
} | ||
} | ||
|
||
export class NotModifiedResponse extends Response { | ||
constructor(...[_body, _init]: ConstructorParameters<typeof Response>) { | ||
super(undefined, { | ||
status: 304, | ||
statusText: "Not Modified", | ||
}); | ||
} | ||
} |
Oops, something went wrong.