@fastly/hono-fastly-compute 0.2.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [unreleased]
9
+
10
+ ## [0.2.0] - 2025-10-06
11
+
12
+ ### Changed
13
+
14
+ - BREAKING: Updated to new identifiers from `@fastly/compute-js-context`
15
+
16
+ ## [0.1.0] - 2025-10-03
17
+
18
+ ### Added
19
+
20
+ - Initial public release
21
+
22
+ [unreleased]: https://github.com/fastly/hono-fastly-compute/compare/v0.2.0...HEAD
23
+ [0.2.0]: https://github.com/fastly/hono-fastly-compute/compare/v0.1.0...v0.2.0
24
+ [0.1.0]: https://github.com/fastly/hono-fastly-compute/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Hono Adapter for Fastly Compute
2
+
3
+ This library provides an adapter for using the [Hono](https://hono.dev/) web framework with [Fastly Compute](https://www.fastly.com/products/edge-compute). It simplifies the process of creating Hono applications that run on Fastly's edge platform.
4
+
5
+ ## Features
6
+
7
+ - **Seamless Integration**: Easily adapt your Hono application to Fastly Compute's event-driven architecture.
8
+ - **Type-Safe Bindings**: Automatically infer types for your Fastly resources (like KV Stores and Config Stores) using the `buildFire` function.
9
+ - **Simplified Setup**: The `buildFire` utility streamlines the process of setting up your application and its environment bindings.
10
+ - **Middleware Utility**: Includes a `logFastlyServiceVersion` middleware for easy debugging and version tracking.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @fastly/hono-fastly-compute
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ Here's a basic example of how to create a Hono application and run it on Fastly Compute.
21
+
22
+ ### Basic Example
23
+
24
+ ```typescript
25
+ import { Hono } from 'hono';
26
+ import { buildFire } from '@fastly/hono-fastly-compute';
27
+
28
+ // buildFire creates a `fire` function bound to your environment bindings.
29
+ // If you have no bindings, pass an empty object.
30
+ const fire = buildFire({
31
+ assets: 'KVStore',
32
+ config: 'ConfigStore:my-config',
33
+ });
34
+
35
+ // Use the inferred Bindings type in your Hono environment
36
+ type Env = {
37
+ Bindings: typeof fire.Bindings;
38
+ };
39
+
40
+ const app = new Hono<Env>();
41
+
42
+ app.get('/', async (c) => {
43
+ // Access your bindings from the context
44
+ const value = await c.env.assets.get('some-key');
45
+ const setting = c.env.config.get('some-setting');
46
+ return c.json({ value, setting });
47
+ });
48
+
49
+ fire(app);
50
+ ```
51
+
52
+ ### Using the `logFastlyServiceVersion` Middleware
53
+
54
+ This package includes a simple middleware to log the `FASTLY_SERVICE_VERSION` for debugging purposes.
55
+
56
+ ```typescript
57
+ import { Hono } from 'hono';
58
+ import { buildFire, logFastlyServiceVersion } from '@fastly/hono-fastly-compute';
59
+
60
+ const fire = buildFire({});
61
+ const app = new Hono();
62
+
63
+ // Use the middleware
64
+ app.use('*', logFastlyServiceVersion());
65
+
66
+ app.get('/', (c) => c.text('Hello!'));
67
+
68
+ fire(app);
69
+ ```
70
+
71
+ ## API
72
+
73
+ ### `buildFire(bindingsDefs)`
74
+
75
+ Creates a `fire` function that is bound to a specific set of environment bindings.
76
+
77
+ - **`bindingsDefs`**: An object mapping binding names to their resource types
78
+ - Keys: The property name used to access the resource
79
+ - Values: A string in the format 'ResourceType'
80
+ - If the actual name of the object differs from the Key, or if its name
81
+ is not a valid JavaScript identifier, use 'ResourceType:actual-name'
82
+ - **Returns**: A `fire` function
83
+
84
+ The returned `fire` function has two purposes:
85
+ 1. When called with a Hono app instance (`fire(app)`), it registers the app to handle fetch events.
86
+ 2. It exposes a `Bindings` type (`typeof fire.Bindings`) that you can use to define your Hono `Env`.
87
+
88
+ ### `handle(app, bindingsDefs, options)`
89
+
90
+ The core adapter function that connects Hono to the Fastly Compute `FetchEvent`. The `buildFire` function is a higher-level utility that uses `handle` internally.
91
+
92
+ - **`app`**: The Hono application instance.
93
+ - **`bindingsDefs`**: The environment bindings definition.
94
+ - **`options`**: An optional object with a `fetch` property.
95
+
96
+ ### `logFastlyServiceVersion()`
97
+
98
+ A middleware for Hono that logs the string `FASTLY_SERVICE_VERSION: <service-version>` environment variable to the console.
99
+
100
+ ## License
101
+
102
+ This project is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,37 @@
1
+ import { Acl } from 'fastly:acl';
2
+ import { Backend } from 'fastly:backend';
3
+ import { ConfigStore } from 'fastly:config-store';
4
+ import { KVStore } from 'fastly:kv-store';
5
+ import { Logger } from 'fastly:logger';
6
+ import { SecretStore } from 'fastly:secret-store';
7
+ import { Context } from "@h7/fastly-compute-js-context";
8
+ type Def<T extends string> = T | `${T}:${string}`;
9
+ type Defs<T extends string> = T extends string ? Def<T> : never;
10
+ declare const BindingStringToContextKeyMapping: {
11
+ readonly Acl: "ACLS";
12
+ readonly Backend: "BACKENDS";
13
+ readonly ConfigStore: "CONFIG_STORES";
14
+ readonly env: "ENV";
15
+ readonly KVStore: "KV_STORES";
16
+ readonly Logger: "LOGGERS";
17
+ readonly SecretStore: "SECRET_STORES";
18
+ };
19
+ export type ResourceType = keyof typeof BindingStringToContextKeyMapping;
20
+ export type BindingsString = Defs<ResourceType>;
21
+ export type EnvBindingsDefs = Record<string, BindingsString>;
22
+ type BindingStringToResourceInstanceTypeMapping = {
23
+ Acl: Acl;
24
+ Backend: Backend;
25
+ ConfigStore: ConfigStore;
26
+ env: string;
27
+ KVStore: KVStore;
28
+ Logger: Logger;
29
+ SecretStore: SecretStore;
30
+ };
31
+ export type ResourceInstance<T> = T extends Def<infer K extends keyof BindingStringToResourceInstanceTypeMapping> ? BindingStringToResourceInstanceTypeMapping[K] : never;
32
+ export type BuildBindings<T extends EnvBindingsDefs> = {
33
+ [K in keyof T]: ResourceInstance<T[K]>;
34
+ };
35
+ export declare function buildEnvironment<T extends EnvBindingsDefs>(context: Context, envBindingsDefs: T): BuildBindings<T>;
36
+ export {};
37
+ //# sourceMappingURL=bindings.d.ts.map
@@ -0,0 +1,53 @@
1
+ const BindingStringToContextKeyMapping = {
2
+ Acl: 'ACLS',
3
+ Backend: 'BACKENDS',
4
+ ConfigStore: 'CONFIG_STORES',
5
+ env: 'ENV',
6
+ KVStore: 'KV_STORES',
7
+ Logger: 'LOGGERS',
8
+ SecretStore: 'SECRET_STORES',
9
+ };
10
+ function isResourceType(resourceType) {
11
+ return resourceType in BindingStringToContextKeyMapping;
12
+ }
13
+ function getResourceType(typeName) {
14
+ const [resourceType,] = typeName.split(':');
15
+ if (isResourceType(resourceType)) {
16
+ return resourceType;
17
+ }
18
+ return undefined;
19
+ }
20
+ function getResourceName(key, typeName) {
21
+ const [, seg,] = typeName.split(':');
22
+ return seg ?? key;
23
+ }
24
+ export function buildEnvironment(context, envBindingsDefs) {
25
+ const target = {};
26
+ const getEntry = (key) => {
27
+ if (typeof key !== "string") {
28
+ return undefined;
29
+ }
30
+ console.log('key', key);
31
+ const typeName = envBindingsDefs[key];
32
+ const resourceType = getResourceType(typeName);
33
+ if (resourceType == null) {
34
+ return undefined;
35
+ }
36
+ const resourceName = getResourceName(key, typeName);
37
+ const contextKey = BindingStringToContextKeyMapping[resourceType];
38
+ const contextEntry = context[contextKey];
39
+ if (contextEntry == null) {
40
+ return undefined;
41
+ }
42
+ return contextEntry[resourceName];
43
+ };
44
+ const handler = {
45
+ get(_, key) {
46
+ return getEntry(key);
47
+ },
48
+ has(_, key) {
49
+ return getEntry(key) !== undefined;
50
+ },
51
+ };
52
+ return new Proxy(target, handler);
53
+ }
@@ -0,0 +1,75 @@
1
+ import type { Schema } from 'hono';
2
+ import type { HonoBase } from 'hono/hono-base';
3
+ import type { ContextProxy, BindingsDefs } from '@fastly/compute-js-context';
4
+ import { type HandleOptions } from './handler.js';
5
+ type FireFn<D extends BindingsDefs> = {
6
+ /**
7
+ * Registers a Hono app to handle fetch events in Fastly Compute.
8
+ *
9
+ * This sets up `addEventListener('fetch', handle(app, envBindingsDefs, options))`
10
+ * using the bindings you passed to `buildFire()`.
11
+ *
12
+ * @param app - The Hono application instance to serve
13
+ * @param options - Options for handling requests (fetch defaults to undefined)
14
+ *
15
+ * @example
16
+ * const fire = buildFire({ foo: "KVStore" });
17
+ *
18
+ * type Env = {
19
+ * Variables: Variables;
20
+ * Bindings: typeof fire.Bindings;
21
+ * };
22
+ *
23
+ * const app = new Hono<Env>();
24
+ * fire(app);
25
+ */
26
+ <V extends {
27
+ Variables?: object;
28
+ }, S extends Schema, BasePath extends string>(app: HonoBase<(keyof D extends never ? {} : {
29
+ Bindings: ContextProxy<D>;
30
+ }) & V, S, BasePath>, options?: HandleOptions): void;
31
+ /**
32
+ * The inferred bindings type, derived from the defs passed to `buildFire()`.
33
+ * Use this in your Env definition: `{ Bindings: typeof fire.Bindings }`.
34
+ */
35
+ Bindings: ContextProxy<D>;
36
+ /** For debugging: the raw defs object you passed to buildFire */
37
+ defs: D;
38
+ };
39
+ /**
40
+ * Creates a `fire` function bound to a specific set of environment bindings.
41
+ *
42
+ * Call `buildFire()` with the shape of your bindings. The returned `fire` function
43
+ * registers your Hono app to handle fetch events in Fastly Compute, and also exposes
44
+ * a `.Bindings` type you can use when defining your `Env`.
45
+ *
46
+ * ### Example: With bindings
47
+ * ```ts
48
+ * const fire = buildFire({ grip: "ConfigStore", foo: "KVStore" });
49
+ *
50
+ * type Env = {
51
+ * Variables: Variables;
52
+ * Bindings: typeof fire.Bindings; // infer binding types automatically
53
+ * };
54
+ *
55
+ * const app = new Hono<Env>();
56
+ * fire(app);
57
+ * ```
58
+ *
59
+ * ### Example: No bindings
60
+ * ```ts
61
+ * const fire = buildFire({});
62
+ *
63
+ * const app = new Hono();
64
+ * fire(app);
65
+ * ```
66
+ *
67
+ * @param bindingsDefs - A mapping of binding names to binding types
68
+ * (e.g. `{ foo: "KVStore", bar: "ConfigStore" }`).
69
+ * @returns A `fire` function that:
70
+ * - Registers your Hono app to handle fetch events
71
+ * - Exposes a `.Bindings` type inferred from the given defs
72
+ */
73
+ export declare function buildFire<D extends BindingsDefs>(bindingsDefs: D): FireFn<D>;
74
+ export {};
75
+ //# sourceMappingURL=fire.d.ts.map
package/build/fire.js ADDED
@@ -0,0 +1,44 @@
1
+ import { handle } from './handler.js';
2
+ /**
3
+ * Creates a `fire` function bound to a specific set of environment bindings.
4
+ *
5
+ * Call `buildFire()` with the shape of your bindings. The returned `fire` function
6
+ * registers your Hono app to handle fetch events in Fastly Compute, and also exposes
7
+ * a `.Bindings` type you can use when defining your `Env`.
8
+ *
9
+ * ### Example: With bindings
10
+ * ```ts
11
+ * const fire = buildFire({ grip: "ConfigStore", foo: "KVStore" });
12
+ *
13
+ * type Env = {
14
+ * Variables: Variables;
15
+ * Bindings: typeof fire.Bindings; // infer binding types automatically
16
+ * };
17
+ *
18
+ * const app = new Hono<Env>();
19
+ * fire(app);
20
+ * ```
21
+ *
22
+ * ### Example: No bindings
23
+ * ```ts
24
+ * const fire = buildFire({});
25
+ *
26
+ * const app = new Hono();
27
+ * fire(app);
28
+ * ```
29
+ *
30
+ * @param bindingsDefs - A mapping of binding names to binding types
31
+ * (e.g. `{ foo: "KVStore", bar: "ConfigStore" }`).
32
+ * @returns A `fire` function that:
33
+ * - Registers your Hono app to handle fetch events
34
+ * - Exposes a `.Bindings` type inferred from the given defs
35
+ */
36
+ export function buildFire(bindingsDefs) {
37
+ const fireFn = ((app, options = {
38
+ fetch: undefined,
39
+ }) => {
40
+ addEventListener('fetch', handle(app, bindingsDefs, options));
41
+ });
42
+ fireFn.defs = bindingsDefs;
43
+ return fireFn;
44
+ }
@@ -0,0 +1,18 @@
1
+ import type { Schema } from 'hono';
2
+ import type { HonoBase } from 'hono/hono-base';
3
+ import { type BindingsDefs, type ContextProxy } from '@fastly/compute-js-context';
4
+ type Handler = (evt: FetchEvent) => void;
5
+ export type HandleOptions = {
6
+ fetch?: typeof fetch;
7
+ };
8
+ export type MaybeBindings<D extends BindingsDefs> = keyof D extends never ? {} : {
9
+ Bindings: ContextProxy<D>;
10
+ };
11
+ /**
12
+ * Adapter for Fastly Compute
13
+ */
14
+ export declare const handle: <D extends BindingsDefs, V extends {
15
+ Variables?: object;
16
+ }, S extends Schema, BasePath extends string>(app: HonoBase<MaybeBindings<D> & V, S, BasePath>, envBindingsDefs: D, opts?: HandleOptions) => Handler;
17
+ export {};
18
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { createContext, buildContextProxy, } from '@fastly/compute-js-context';
2
+ /**
3
+ * Adapter for Fastly Compute
4
+ */
5
+ export const handle = (app, envBindingsDefs, opts = {
6
+ // To use `fetch` on a Service Worker correctly, bind it to `globalThis`.
7
+ fetch: globalThis.fetch.bind(globalThis),
8
+ }) => {
9
+ return (evt) => {
10
+ evt.respondWith((async () => {
11
+ const context = createContext();
12
+ const env = buildContextProxy(context, envBindingsDefs);
13
+ const res = await app.fetch(evt.request, env, {
14
+ waitUntil: evt.waitUntil.bind(evt),
15
+ passThroughOnException() {
16
+ throw new Error('Not implemented');
17
+ },
18
+ props: undefined,
19
+ });
20
+ if (opts.fetch && res.status === 404) {
21
+ return await opts.fetch(evt.request);
22
+ }
23
+ return res;
24
+ })());
25
+ };
26
+ };
@@ -0,0 +1,5 @@
1
+ export * from './fire.js';
2
+ export * from './handler.js';
3
+ export * from './utils.js';
4
+ export type { ResourceType, Context, ContextProxy, BindingsDefs, } from '@fastly/compute-js-context';
5
+ //# sourceMappingURL=index.d.ts.map
package/build/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './fire.js';
2
+ export * from './handler.js';
3
+ export * from './utils.js';
@@ -0,0 +1,2 @@
1
+ export declare const logFastlyServiceVersion: () => import("hono").MiddlewareHandler<any, string, {}>;
2
+ //# sourceMappingURL=utils.d.ts.map
package/build/utils.js ADDED
@@ -0,0 +1,6 @@
1
+ import { env } from 'fastly:env';
2
+ import { createMiddleware } from 'hono/factory';
3
+ export const logFastlyServiceVersion = () => createMiddleware(async (_, next) => {
4
+ console.log('FASTLY_SERVICE_VERSION', env('FASTLY_SERVICE_VERSION'));
5
+ await next();
6
+ });
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@fastly/hono-fastly-compute",
3
+ "version": "0.2.0",
4
+ "description": "Helper utilities for using Hono with Fastly Compute",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/fastly/hono-fastly-compute.git"
9
+ },
10
+ "author": {
11
+ "name": "Katsuyuki Omuro",
12
+ "email": "komuro@fastly.com"
13
+ },
14
+ "type": "module",
15
+ "main": "./build/index.js",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./build/index.d.ts",
19
+ "import": "./build/index.js"
20
+ }
21
+ },
22
+ "types": "./build/index.d.ts",
23
+ "scripts": {
24
+ "prepack": "npm run build",
25
+ "build": "tsc -p tsconfig.build.json",
26
+ "clean": "rm -rf build"
27
+ },
28
+ "dependencies": {
29
+ "@fastly/js-compute": "^3.0.0",
30
+ "@fastly/compute-js-context": "^0.3.0"
31
+ },
32
+ "devDependencies": {
33
+ "hono": "^4.9.5",
34
+ "typescript": "^5.4.5"
35
+ },
36
+ "peerDependencies": {
37
+ "@fastly/js-compute": "^3.0.0",
38
+ "hono": "^4.5.0"
39
+ },
40
+ "files": [
41
+ "build/**/*.js",
42
+ "build/**/*.js.map",
43
+ "build/**/*.d.ts",
44
+ "LICENSE",
45
+ "README.md",
46
+ "CHANGELOG.md"
47
+ ],
48
+ "keywords": [
49
+ "hono",
50
+ "fastly",
51
+ "compute"
52
+ ]
53
+ }