@fastly/compute-js-context 0.3.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 +27 -0
- package/LICENSE +19 -0
- package/README.md +157 -0
- package/build/acls.d.ts +5 -0
- package/build/acls.js +18 -0
- package/build/backends.d.ts +5 -0
- package/build/backends.js +18 -0
- package/build/bindings.d.ts +37 -0
- package/build/bindings.js +52 -0
- package/build/config-stores.d.ts +5 -0
- package/build/config-stores.js +18 -0
- package/build/context.d.ts +18 -0
- package/build/context.js +26 -0
- package/build/env.d.ts +14 -0
- package/build/env.js +11 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +6 -0
- package/build/kv-stores.d.ts +5 -0
- package/build/kv-stores.js +18 -0
- package/build/loggers.d.ts +5 -0
- package/build/loggers.js +18 -0
- package/build/proxy.d.ts +37 -0
- package/build/proxy.js +56 -0
- package/build/secret-stores.d.ts +5 -0
- package/build/secret-stores.js +18 -0
- package/build/util.d.ts +3 -0
- package/build/util.js +28 -0
- package/package.json +48 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
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.3.0] - 2025-10-06
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- BREAKING: Some identifiers renamed:
|
|
15
|
+
- `buildEnvironment` -> `buildContextProxy`
|
|
16
|
+
- `BuildBindings` -> `ContextProxy`
|
|
17
|
+
- `EnvBindingsDefs` -> `BindingsDefs`
|
|
18
|
+
|
|
19
|
+
## [0.2.0] - 2025-10-03
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Initial public release
|
|
24
|
+
|
|
25
|
+
[unreleased]: https://github.com/fastly/compute-js-context/compare/v0.3.0...HEAD
|
|
26
|
+
[0.3.0]: https://github.com/fastly/compute-js-context/compare/v0.2.0...v0.3.0
|
|
27
|
+
[0.2.0]: https://github.com/fastly/compute-js-context/releases/tag/v0.2.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,157 @@
|
|
|
1
|
+
# Fastly Compute Context Utility
|
|
2
|
+
|
|
3
|
+
`@fastly/compute-js-context` exposes Fastly Compute resources to your Compute JavaScript application. It provides it as one typed, immutable context object, or as a custom, strongly-typed object mapping your service's specific resource names to their handles.
|
|
4
|
+
|
|
5
|
+
## The `Context` Object
|
|
6
|
+
|
|
7
|
+
The core export is `createContext`, which returns a single, immutable `Context` object.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
type Context = Readonly<{
|
|
11
|
+
ACLS: Acls;
|
|
12
|
+
BACKENDS: Backends;
|
|
13
|
+
CONFIG_STORES: ConfigStores;
|
|
14
|
+
ENV: Env;
|
|
15
|
+
KV_STORES: KVStores;
|
|
16
|
+
LOGGERS: Loggers;
|
|
17
|
+
SECRET_STORES: SecretStores;
|
|
18
|
+
}>;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each top-level field is a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). Accessing a property lazily looks up and caches the corresponding runtime object. Unknown names return `undefined`.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **A single source of truth**: grab everything off `ctx.*`
|
|
26
|
+
- **Typed and safe**: TypeScript-first, with `undefined` for optional resources
|
|
27
|
+
- **Lazy + memoized**: nothing is created until accessed
|
|
28
|
+
- **Readonly**: the `Context` is immutable
|
|
29
|
+
- **Customizable**: use `buildContextProxy` to create a bespoke, typed binding object for your app
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
> Requires a [Fastly Compute JavaScript project (`@fastly/js-compute`)](https://www.fastly.com/documentation/guides/compute/developer-guides/javascript/).
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @fastly/compute-js-context
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
This example shows basic usage of the main `Context` object.
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
/// <reference types="@fastly/js-compute" />
|
|
45
|
+
import { createContext } from '@fastly/compute-js-context';
|
|
46
|
+
|
|
47
|
+
addEventListener('fetch', (event) => event.respondWith(handler(event)));
|
|
48
|
+
async function handler(event) {
|
|
49
|
+
const ctx = createContext();
|
|
50
|
+
|
|
51
|
+
// Environment - simple strings (or empty string if not present)
|
|
52
|
+
console.log('FASTLY_SERVICE_VERSION', ctx.ENV.FASTLY_SERVICE_VERSION);
|
|
53
|
+
|
|
54
|
+
// Secret Store - property is the SecretStore object, or undefined if not configured
|
|
55
|
+
const awsSecrets = ctx.SECRET_STORES.AWS_CREDENTIALS;
|
|
56
|
+
const keyId = await awsSecrets?.get('AWS_ACCESS_KEY_ID');
|
|
57
|
+
console.log('key id', keyId?.plaintext());
|
|
58
|
+
|
|
59
|
+
// Backend - pass to fetch() options, or learn about the backend
|
|
60
|
+
const origin = ctx.BACKENDS.origin;
|
|
61
|
+
const res = await fetch("/", { backend: origin });
|
|
62
|
+
|
|
63
|
+
// Logger - send output to a named Fastly logging endpoint.
|
|
64
|
+
const myLogEndpoint = ctx.LOGGERS.my_log_endpoint;
|
|
65
|
+
myLogEndpoint?.log(`${event.request.url} ${event.client.address}`);
|
|
66
|
+
|
|
67
|
+
return new Response("ok");
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Typed Bindings with `buildContextProxy`
|
|
72
|
+
|
|
73
|
+
For an even better developer experience, `buildContextProxy` creates a typed object that maps your application's specific binding names to the underlying Fastly resources. This gives you shorter names and better autocompletion.
|
|
74
|
+
|
|
75
|
+
First, define your bindings. The key is the name you want to use, and the value is a string identifying the resource type and (optionally) the resource name if it differs from the key.
|
|
76
|
+
|
|
77
|
+
Then, pass these definitions to `buildContextProxy()`.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
/// <reference types="@fastly/js-compute" />
|
|
81
|
+
import { createContext, buildContextProxy, type BindingsDefs } from '@fastly/compute-js-context';
|
|
82
|
+
|
|
83
|
+
// Define your application's bindings
|
|
84
|
+
const bindingsDefs = {
|
|
85
|
+
// Simple mapping: key 'assets' maps to KVStore named 'assets'
|
|
86
|
+
assets: 'KVStore',
|
|
87
|
+
|
|
88
|
+
// Remapping: key 'origin' maps to Backend named 'origin-s3'
|
|
89
|
+
origin: 'Backend:origin-s3',
|
|
90
|
+
|
|
91
|
+
// Explicit mapping for a logger
|
|
92
|
+
auditLog: 'Logger:audit_log',
|
|
93
|
+
} satisfies BindingsDefs; // <-- for full type safety
|
|
94
|
+
|
|
95
|
+
// This is the generated type for your bindings object
|
|
96
|
+
type Bindings = BuildBindings<typeof bindingsDefs>;
|
|
97
|
+
|
|
98
|
+
addEventListener('fetch', (event) => event.respondWith(handler(event)));
|
|
99
|
+
async function handler(event: FetchEvent): Promise<Response> {
|
|
100
|
+
const ctx = createContext();
|
|
101
|
+
|
|
102
|
+
// Create the typed environment
|
|
103
|
+
const bindings: Bindings = buildContextProxy(ctx, bindingsDefs);
|
|
104
|
+
|
|
105
|
+
// Now use your custom bindings!
|
|
106
|
+
const asset = await bindings.assets?.get('/index.html');
|
|
107
|
+
|
|
108
|
+
const res = await fetch("/", { backend: bindings.origin });
|
|
109
|
+
|
|
110
|
+
bindings.auditLog?.log('Request received');
|
|
111
|
+
|
|
112
|
+
return new Response(asset);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## API
|
|
117
|
+
|
|
118
|
+
### `createContext(): Context`
|
|
119
|
+
|
|
120
|
+
Creates the main immutable `Context`. Each sub-object is a `Proxy` that:
|
|
121
|
+
|
|
122
|
+
- **Resolves lazily** on first property access
|
|
123
|
+
- **Caches** the resolved handle for subsequent accesses
|
|
124
|
+
- **Returns `undefined`** for names that don’t exist (except for `ENV`, which returns `''`)
|
|
125
|
+
- **Is not enumerable** by design (don’t rely on `Object.keys`)
|
|
126
|
+
|
|
127
|
+
### `buildContextProxy<T>(context: Context, bindingsDefs: T): BuildBindings<T>`
|
|
128
|
+
|
|
129
|
+
Creates a custom, strongly-typed proxy object based on your definitions.
|
|
130
|
+
|
|
131
|
+
- `context`: An instance of the main `Context` object
|
|
132
|
+
- `bindingsDefs`: A `const` object defining your desired bindings
|
|
133
|
+
- **Key**: The property name you want on your final `contextProxy` object
|
|
134
|
+
- **Value**: A string in the format `'ResourceType'` or `'ResourceType:actual-name'`
|
|
135
|
+
- **Returns**: A proxy object `contextProxy` with your custom bindings. Accessing a property on this object looks up the resource from the main `Context`
|
|
136
|
+
|
|
137
|
+
### Context Categories & Shapes
|
|
138
|
+
|
|
139
|
+
> These are the raw shapes available on the main `Context` object.
|
|
140
|
+
|
|
141
|
+
- **`ENV`**: `Readonly<Record<string, string>>`
|
|
142
|
+
- **`SECRET_STORES`**: `Readonly<Record<string, SecretStore | undefined>>`
|
|
143
|
+
- **`CONFIG_STORES`**: `Readonly<Record<string, ConfigStore | undefined>>`
|
|
144
|
+
- **`KV_STORES`**: `Readonly<Record<string, KVStore | undefined>>`
|
|
145
|
+
- **`BACKENDS`**: `Readonly<Record<string, Backend | undefined>>`
|
|
146
|
+
- **`LOGGERS`**: `Readonly<Record<string, Logger | undefined>>`
|
|
147
|
+
- **`ACLS`**: `Readonly<Record<string, Acl | undefined>>`
|
|
148
|
+
|
|
149
|
+
## Caveats
|
|
150
|
+
|
|
151
|
+
- **Don’t enumerate** category proxies; treat them as name-indexed lookups
|
|
152
|
+
- **Don’t mutate** the context or its sub-objects; it’s intentionally `Readonly`
|
|
153
|
+
- **Expect `undefined`** for missing resources and code accordingly (`?.`/guard)
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
[MIT](./LICENSE).
|
package/build/acls.d.ts
ADDED
package/build/acls.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { Acl } from 'fastly:acl';
|
|
6
|
+
import { loadOptionalStringMap } from "./util.js";
|
|
7
|
+
export function createAcls() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let acl;
|
|
10
|
+
try {
|
|
11
|
+
acl = Acl.open(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
acl = undefined;
|
|
15
|
+
}
|
|
16
|
+
return acl;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { Backend } from 'fastly:backend';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createBackends() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let backend;
|
|
10
|
+
try {
|
|
11
|
+
backend = Backend.fromName(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
backend = undefined;
|
|
15
|
+
}
|
|
16
|
+
return backend;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Acl } from 'fastly:acl';
|
|
2
|
+
import type { Backend } from 'fastly:backend';
|
|
3
|
+
import type { ConfigStore } from 'fastly:config-store';
|
|
4
|
+
import type { KVStore } from 'fastly:kv-store';
|
|
5
|
+
import type { Logger } from 'fastly:logger';
|
|
6
|
+
import type { SecretStore } from 'fastly:secret-store';
|
|
7
|
+
import type { Context } from './index.js';
|
|
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,52 @@
|
|
|
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
|
+
const typeName = envBindingsDefs[key];
|
|
31
|
+
const resourceType = getResourceType(typeName);
|
|
32
|
+
if (resourceType == null) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const resourceName = getResourceName(key, typeName);
|
|
36
|
+
const contextKey = BindingStringToContextKeyMapping[resourceType];
|
|
37
|
+
const contextEntry = context[contextKey];
|
|
38
|
+
if (contextEntry == null) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return contextEntry[resourceName];
|
|
42
|
+
};
|
|
43
|
+
const handler = {
|
|
44
|
+
get(_, key) {
|
|
45
|
+
return getEntry(key);
|
|
46
|
+
},
|
|
47
|
+
has(_, key) {
|
|
48
|
+
return getEntry(key) !== undefined;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return new Proxy(target, handler);
|
|
52
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ConfigStore } from 'fastly:config-store';
|
|
2
|
+
import { type ReadonlyOptionalMap } from './util.js';
|
|
3
|
+
export type ConfigStores = ReadonlyOptionalMap<ConfigStore>;
|
|
4
|
+
export declare function createConfigStores(): ConfigStores;
|
|
5
|
+
//# sourceMappingURL=config-stores.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { ConfigStore } from 'fastly:config-store';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createConfigStores() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let configStore;
|
|
10
|
+
try {
|
|
11
|
+
configStore = new ConfigStore(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
configStore = undefined;
|
|
15
|
+
}
|
|
16
|
+
return configStore;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Acls } from './acls.js';
|
|
2
|
+
import { type Backends } from './backends.js';
|
|
3
|
+
import { type ConfigStores } from './config-stores.js';
|
|
4
|
+
import { type Env } from './env.js';
|
|
5
|
+
import { type KVStores } from './kv-stores.js';
|
|
6
|
+
import { type Loggers } from './loggers.js';
|
|
7
|
+
import { type SecretStores } from './secret-stores.js';
|
|
8
|
+
export type Context = Readonly<{
|
|
9
|
+
ACLS: Acls;
|
|
10
|
+
BACKENDS: Backends;
|
|
11
|
+
CONFIG_STORES: ConfigStores;
|
|
12
|
+
ENV: Env;
|
|
13
|
+
KV_STORES: KVStores;
|
|
14
|
+
LOGGERS: Loggers;
|
|
15
|
+
SECRET_STORES: SecretStores;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function createContext(): Context;
|
|
18
|
+
//# sourceMappingURL=context.d.ts.map
|
package/build/context.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { createAcls } from './acls.js';
|
|
6
|
+
import { createBackends } from './backends.js';
|
|
7
|
+
import { createConfigStores } from './config-stores.js';
|
|
8
|
+
import { createEnv } from './env.js';
|
|
9
|
+
import { createKVStores } from './kv-stores.js';
|
|
10
|
+
import { createLoggers } from './loggers.js';
|
|
11
|
+
import { createSecretStores } from './secret-stores.js';
|
|
12
|
+
let _ctx = undefined;
|
|
13
|
+
export function createContext() {
|
|
14
|
+
if (_ctx === undefined) {
|
|
15
|
+
_ctx = Object.freeze({
|
|
16
|
+
ACLS: createAcls(),
|
|
17
|
+
BACKENDS: createBackends(),
|
|
18
|
+
CONFIG_STORES: createConfigStores(),
|
|
19
|
+
ENV: createEnv(),
|
|
20
|
+
KV_STORES: createKVStores(),
|
|
21
|
+
LOGGERS: createLoggers(),
|
|
22
|
+
SECRET_STORES: createSecretStores(),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return _ctx;
|
|
26
|
+
}
|
package/build/env.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Env = {
|
|
2
|
+
FASTLY_CACHE_GENERATION?: string;
|
|
3
|
+
FASTLY_CUSTOMER_ID?: string;
|
|
4
|
+
FASTLY_HOSTNAME?: string;
|
|
5
|
+
FASTLY_IS_STAGING?: string;
|
|
6
|
+
FASTLY_POP?: string;
|
|
7
|
+
FASTLY_REGION?: string;
|
|
8
|
+
FASTLY_SERVICE_ID?: string;
|
|
9
|
+
FASTLY_SERVICE_VERSION?: string;
|
|
10
|
+
FASTLY_TRACE_ID?: string;
|
|
11
|
+
[key: string]: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
export declare function createEnv(): Env;
|
|
14
|
+
//# sourceMappingURL=env.d.ts.map
|
package/build/env.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { env } from 'fastly:env';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createEnv() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
return env(name);
|
|
10
|
+
});
|
|
11
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { KVStore } from 'fastly:kv-store';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createKVStores() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let kvStore;
|
|
10
|
+
try {
|
|
11
|
+
kvStore = new KVStore(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
kvStore = undefined;
|
|
15
|
+
}
|
|
16
|
+
return kvStore;
|
|
17
|
+
});
|
|
18
|
+
}
|
package/build/loggers.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from 'fastly:logger';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createLoggers() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let logger;
|
|
10
|
+
try {
|
|
11
|
+
logger = new Logger(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
logger = undefined;
|
|
15
|
+
}
|
|
16
|
+
return logger;
|
|
17
|
+
});
|
|
18
|
+
}
|
package/build/proxy.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Acl } from 'fastly:acl';
|
|
2
|
+
import type { Backend } from 'fastly:backend';
|
|
3
|
+
import type { ConfigStore } from 'fastly:config-store';
|
|
4
|
+
import type { KVStore } from 'fastly:kv-store';
|
|
5
|
+
import type { Logger } from 'fastly:logger';
|
|
6
|
+
import type { SecretStore } from 'fastly:secret-store';
|
|
7
|
+
import type { Context } from './index.js';
|
|
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 BindingsDefs = 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 ContextProxy<T extends BindingsDefs> = {
|
|
33
|
+
[K in keyof T]: ResourceInstance<T[K]>;
|
|
34
|
+
};
|
|
35
|
+
export declare function buildContextProxy<T extends BindingsDefs>(context: Context, bindingsDefs: T): ContextProxy<T>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=proxy.d.ts.map
|
package/build/proxy.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
const BindingStringToContextKeyMapping = {
|
|
6
|
+
Acl: 'ACLS',
|
|
7
|
+
Backend: 'BACKENDS',
|
|
8
|
+
ConfigStore: 'CONFIG_STORES',
|
|
9
|
+
env: 'ENV',
|
|
10
|
+
KVStore: 'KV_STORES',
|
|
11
|
+
Logger: 'LOGGERS',
|
|
12
|
+
SecretStore: 'SECRET_STORES',
|
|
13
|
+
};
|
|
14
|
+
function isResourceType(resourceType) {
|
|
15
|
+
return resourceType in BindingStringToContextKeyMapping;
|
|
16
|
+
}
|
|
17
|
+
function getResourceType(typeName) {
|
|
18
|
+
const [resourceType,] = typeName.split(':');
|
|
19
|
+
if (isResourceType(resourceType)) {
|
|
20
|
+
return resourceType;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function getResourceName(key, typeName) {
|
|
25
|
+
const [, seg,] = typeName.split(':');
|
|
26
|
+
return seg ?? key;
|
|
27
|
+
}
|
|
28
|
+
export function buildContextProxy(context, bindingsDefs) {
|
|
29
|
+
const target = {};
|
|
30
|
+
const getEntry = (key) => {
|
|
31
|
+
if (typeof key !== "string") {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const typeName = bindingsDefs[key];
|
|
35
|
+
const resourceType = getResourceType(typeName);
|
|
36
|
+
if (resourceType == null) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const resourceName = getResourceName(key, typeName);
|
|
40
|
+
const contextKey = BindingStringToContextKeyMapping[resourceType];
|
|
41
|
+
const contextEntry = context[contextKey];
|
|
42
|
+
if (contextEntry == null) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return contextEntry[resourceName];
|
|
46
|
+
};
|
|
47
|
+
const handler = {
|
|
48
|
+
get(_, key) {
|
|
49
|
+
return getEntry(key);
|
|
50
|
+
},
|
|
51
|
+
has(_, key) {
|
|
52
|
+
return getEntry(key) !== undefined;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
return new Proxy(target, handler);
|
|
56
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SecretStore } from 'fastly:secret-store';
|
|
2
|
+
import { type ReadonlyOptionalMap } from './util.js';
|
|
3
|
+
export type SecretStores = ReadonlyOptionalMap<SecretStore>;
|
|
4
|
+
export declare function createSecretStores(): SecretStores;
|
|
5
|
+
//# sourceMappingURL=secret-stores.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
import { SecretStore } from 'fastly:secret-store';
|
|
6
|
+
import { loadOptionalStringMap } from './util.js';
|
|
7
|
+
export function createSecretStores() {
|
|
8
|
+
return loadOptionalStringMap((name) => {
|
|
9
|
+
let secretStore;
|
|
10
|
+
try {
|
|
11
|
+
secretStore = new SecretStore(name); // throws if not found or not provisioned
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
secretStore = undefined;
|
|
15
|
+
}
|
|
16
|
+
return secretStore;
|
|
17
|
+
});
|
|
18
|
+
}
|
package/build/util.d.ts
ADDED
package/build/util.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Fastly, Inc.
|
|
3
|
+
* Licensed under the MIT license. See LICENSE file for details.
|
|
4
|
+
*/
|
|
5
|
+
export function loadOptionalStringMap(getter) {
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
const target = {};
|
|
8
|
+
const getEntry = (key) => {
|
|
9
|
+
if (typeof key !== "string") {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
if (cache.has(key)) {
|
|
13
|
+
return cache.get(key);
|
|
14
|
+
}
|
|
15
|
+
const entry = getter(key);
|
|
16
|
+
cache.set(key, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
const handler = {
|
|
20
|
+
get(_, key) {
|
|
21
|
+
return getEntry(key);
|
|
22
|
+
},
|
|
23
|
+
has(_, key) {
|
|
24
|
+
return getEntry(key) !== undefined;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
return new Proxy(target, handler);
|
|
28
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fastly/compute-js-context",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Surfaces Fastly Compute environment as a context object",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/fastly/compute-js-context.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
|
+
"devDependencies": {
|
|
29
|
+
"@fastly/js-compute": "^3.34.0",
|
|
30
|
+
"typescript": "^5.9.2"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@fastly/js-compute": "^3.32.0"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"build/**/*.js",
|
|
37
|
+
"build/**/*.js.map",
|
|
38
|
+
"build/**/*.d.ts",
|
|
39
|
+
"LICENSE",
|
|
40
|
+
"README.md",
|
|
41
|
+
"CHANGELOG.md"
|
|
42
|
+
],
|
|
43
|
+
"keywords": [
|
|
44
|
+
"fastly",
|
|
45
|
+
"compute",
|
|
46
|
+
"context"
|
|
47
|
+
]
|
|
48
|
+
}
|