@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 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).
@@ -0,0 +1,5 @@
1
+ import { Acl } from 'fastly:acl';
2
+ import { type ReadonlyOptionalMap } from "./util.js";
3
+ export type Acls = ReadonlyOptionalMap<Acl>;
4
+ export declare function createAcls(): Acls;
5
+ //# sourceMappingURL=acls.d.ts.map
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,5 @@
1
+ import { Backend } from 'fastly:backend';
2
+ import { type ReadonlyOptionalMap } from './util.js';
3
+ export type Backends = ReadonlyOptionalMap<Backend>;
4
+ export declare function createBackends(): Backends;
5
+ //# sourceMappingURL=backends.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 { 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
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export * from './context.js';
2
+ export * from './proxy.js';
3
+ //# sourceMappingURL=index.d.ts.map
package/build/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Copyright Fastly, Inc.
3
+ * Licensed under the MIT license. See LICENSE file for details.
4
+ */
5
+ export * from './context.js';
6
+ export * from './proxy.js';
@@ -0,0 +1,5 @@
1
+ import { KVStore } from 'fastly:kv-store';
2
+ import { type ReadonlyOptionalMap } from './util.js';
3
+ export type KVStores = ReadonlyOptionalMap<KVStore>;
4
+ export declare function createKVStores(): KVStores;
5
+ //# sourceMappingURL=kv-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 { 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
+ }
@@ -0,0 +1,5 @@
1
+ import { Logger } from 'fastly:logger';
2
+ import { type ReadonlyOptionalMap } from './util.js';
3
+ export type Loggers = ReadonlyOptionalMap<Logger>;
4
+ export declare function createLoggers(): Loggers;
5
+ //# sourceMappingURL=loggers.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 { 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
+ }
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export type ReadonlyOptionalMap<T> = Readonly<Record<string, T | undefined>>;
2
+ export declare function loadOptionalStringMap<T>(getter: (key: string) => T | undefined): ReadonlyOptionalMap<T>;
3
+ //# sourceMappingURL=util.d.ts.map
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
+ }