diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index a03246a9..b88c0e48 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -31,11 +31,9 @@ "@astrojs/underscore-redirects": "^0.3.3", "@cloudflare/workers-types": "^4.20240320.1", "miniflare": "^3.20240314.0", - "@iarna/toml": "^2.2.5", - "dotenv": "^16.3.1", "esbuild": "^0.19.5", - "find-up": "^6.3.0", - "tiny-glob": "^0.2.9" + "tiny-glob": "^0.2.9", + "wrangler": "^3.36.0" }, "peerDependencies": { "astro": "^4.2.0" @@ -43,11 +41,9 @@ "devDependencies": { "execa": "^8.0.1", "fast-glob": "^3.3.2", - "@types/iarna__toml": "^2.0.2", "strip-ansi": "^7.1.0", "astro": "^4.5.8", "cheerio": "1.0.0-rc.12", - "wrangler": "^3.36.0", "@astrojs/test-utils": "workspace:*", "astro-scripts": "workspace:*" }, diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 996bd619..269b7a82 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -1,5 +1,4 @@ import type { AstroConfig, AstroIntegration, RouteData } from 'astro'; -import type { LocalPagesRuntime, LocalWorkersRuntime, RUNTIME } from './utils/local-runtime.js'; import * as fs from 'node:fs'; import * as os from 'node:os'; @@ -12,11 +11,11 @@ import glob from 'tiny-glob'; import { getAdapter } from './getAdapter.js'; import { deduplicatePatterns } from './utils/deduplicatePatterns.js'; import { prepareImageConfig } from './utils/image-config.js'; -import { getLocalRuntime, getRuntimeConfig } from './utils/local-runtime.js'; import { prependForwardSlash } from './utils/prependForwardSlash.js'; import { rewriteWasmImportPath } from './utils/rewriteWasmImportPath.js'; import { patchSharpBundle } from './utils/sharpBundlePatch.js'; import { wasmModuleLoader } from './utils/wasm-module-loader.js'; +import { getPlatformProxy } from 'wrangler'; export type { AdvancedRuntime } from './entrypoints/server.advanced.js'; @@ -36,22 +35,18 @@ export type Options = { exclude?: string[]; }; /** - * { mode: 'off' }: current behaviour (wrangler is needed) - * { mode: 'local', ... }: adds cf request object, locals bindings, env vars/secrets which are defined by the user to `astro.dev` with `Astro.locals.runtime` / `context.locals.runtime` + * Proxy configuration for the platform. */ - runtime?: - | { mode: 'off' } - | { - mode: Extract['mode']; - type: Extract['type']; - persistTo?: Extract['persistTo']; - bindings?: Extract['bindings']; - } - | { - mode: Extract['mode']; - type: Extract['type']; - persistTo?: Extract['persistTo']; - }; + platformProxy?: { + /** Toggle the proxy. Default `undefined`, which equals to `false`. */ + enabled?: boolean; + /** Path to the configuration file. Default `wrangler.toml`. */ + configPath?: string; + /** Enable experimental support for JSON configuration. Default `false`. */ + experimentalJsonConfig?: boolean; + /** Configuration persistence settings. Default '.wrangler/state/v3' */ + persist?: boolean | { path: string }; + }; wasmModuleImports?: boolean; }; @@ -66,12 +61,9 @@ interface BuildConfig { export default function createIntegration(args?: Options): AstroIntegration { let _config: AstroConfig; let _buildConfig: BuildConfig; - let _localRuntime: LocalPagesRuntime | LocalWorkersRuntime; const SERVER_BUILD_FOLDER = '/$server_build/'; - const runtimeMode = getRuntimeConfig(args?.runtime); - return { name: '@astrojs/cloudflare', hooks: { @@ -112,41 +104,29 @@ export default function createIntegration(args?: Options): AstroIntegration { ); } }, - 'astro:server:setup': ({ server, logger }) => { - if (runtimeMode.mode === 'local') { - server.middlewares.use(async function middleware(req, res, next) { - _localRuntime = getLocalRuntime(_config, runtimeMode, logger); + 'astro:server:setup': async ({ server, logger }) => { + if (args?.platformProxy?.enabled === true) { + const platformProxy = await getPlatformProxy({ + configPath: args.platformProxy.configPath ?? 'wrangler.toml', + experimentalJsonConfig: args.platformProxy.experimentalJsonConfig ?? false, + persist: args.platformProxy.persist ?? true, + }); - const bindings = await _localRuntime.getBindings(); - const secrets = await _localRuntime.getSecrets(); - const caches = await _localRuntime.getCaches(); - const cf = await _localRuntime.getCF(); + const clientLocalsSymbol = Symbol.for('astro.locals'); - const clientLocalsSymbol = Symbol.for('astro.locals'); + server.middlewares.use(async function middleware(req, res, next) { Reflect.set(req, clientLocalsSymbol, { runtime: { - env: { - CF_PAGES_URL: `http://${req.headers.host}`, - ...bindings, - ...secrets, - }, - cf: cf, - caches: caches, - waitUntil: (_promise: Promise) => { - return; - }, + env: platformProxy.env, + cf: platformProxy.cf, + caches: platformProxy.caches, + ctx: platformProxy.ctx, }, }); next(); }); } }, - 'astro:server:done': async ({ logger }) => { - if (_localRuntime) { - logger.info('Cleaning up the local Cloudflare runtime.'); - await _localRuntime.dispose(); - } - }, 'astro:build:setup': ({ vite, target }) => { if (target === 'server') { vite.resolve ||= {}; diff --git a/packages/cloudflare/src/tmp-types.d.ts b/packages/cloudflare/src/tmp-types.d.ts deleted file mode 100644 index e9efa7f0..00000000 --- a/packages/cloudflare/src/tmp-types.d.ts +++ /dev/null @@ -1,139 +0,0 @@ -type CF_Json = import('miniflare').Json; -type CF_Request = import('miniflare').Request; -type CF_Response = import('miniflare').Response; - -interface CF_RawConfig { - /** - * The name of your worker. Alphanumeric + dashes only. - * - * @inheritable - */ - name: string | undefined; - /** - * These specify any Workers KV Namespaces you want to - * access from inside your Worker. - * - * To learn more about KV Namespaces, - * see the documentation at https://developers.cloudflare.com/workers/learning/how-kv-works - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `[]` - * @nonInheritable - */ - kv_namespaces: { - /** The binding name used to refer to the KV Namespace */ - binding: string; - /** The ID of the KV namespace */ - id: string; - /** The ID of the KV namespace used during `wrangler dev` */ - preview_id?: string; - }[]; - /** - * A map of environment variables to set when deploying your worker. - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `{}` - * @nonInheritable - */ - vars: Record; - /** - * Specifies D1 databases that are bound to this Worker environment. - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `[]` - * @nonInheritable - */ - d1_databases: { - /** The binding name used to refer to the D1 database in the worker. */ - binding: string; - /** The name of this D1 database. */ - database_name: string; - /** The UUID of this D1 database (not required). */ - database_id: string; - /** The UUID of this D1 database for Wrangler Dev (if specified). */ - preview_database_id?: string; - /** The name of the migrations table for this D1 database (defaults to 'd1_migrations'). */ - migrations_table?: string; - /** The path to the directory of migrations for this D1 database (defaults to './migrations'). */ - migrations_dir?: string; - /** Internal use only. */ - database_internal_env?: string; - }[]; - /** - * Specifies R2 buckets that are bound to this Worker environment. - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `[]` - * @nonInheritable - */ - r2_buckets: { - /** The binding name used to refer to the R2 bucket in the worker. */ - binding: string; - /** The name of this R2 bucket at the edge. */ - bucket_name: string; - /** The preview name of this R2 bucket at the edge. */ - preview_bucket_name?: string; - /** The jurisdiction that the bucket exists in. Default if not present. */ - jurisdiction?: string; - }[]; - /** - * A list of durable objects that your worker should be bound to. - * - * For more information about Durable Objects, see the documentation at - * https://developers.cloudflare.com/workers/learning/using-durable-objects - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `{bindings:[]}` - * @nonInheritable - */ - durable_objects: { - bindings: { - /** The name of the binding used to refer to the Durable Object */ - name: string; - /** The exported class name of the Durable Object */ - class_name: string; - /** The script where the Durable Object is defined (if it's external to this worker) */ - script_name?: string; - /** The service environment of the script_name to bind to */ - environment?: string; - }[]; - }; - /** - * A list of service bindings that your worker should be bound to. - * - * For more information about Service bindings, see the documentation at - * https://developers.cloudflare.com/workers/configuration/bindings/about-service-bindings/ - * - * NOTE: This field is not automatically inherited from the top level environment, - * and so must be specified in every named environment. - * - * @default `[]` - * @nonInheritable - */ - services: { - binding: string; - service: string; - }[]; -} - -interface CF_ServiceDesignator { - name: string; - env?: string; -} - -type CF_ServiceFetch = (request: CF_Request) => Promise | CF_Response; - -type CF_File = - | { path: string } // `path` resolved relative to cwd - | { contents: Contents; path?: string }; // `contents` used instead, `path` can be specified if needed e.g. for module resolution -type CF_BinaryFile = CF_File; // Note: Node's `Buffer`s are instances of `Uint8Array` diff --git a/packages/cloudflare/src/utils/local-runtime.ts b/packages/cloudflare/src/utils/local-runtime.ts deleted file mode 100644 index e9e5aab8..00000000 --- a/packages/cloudflare/src/utils/local-runtime.ts +++ /dev/null @@ -1,368 +0,0 @@ -import type { - D1Database, - DurableObjectNamespace, - IncomingRequestCfProperties, - KVNamespace, - R2Bucket, -} from '@cloudflare/workers-types/experimental'; -import type { AstroConfig, AstroIntegrationLogger } from 'astro'; -import type { ExternalServer, Json, ReplaceWorkersTypes, WorkerOptions } from 'miniflare'; -import type { Options } from '../index.js'; - -import assert from 'node:assert'; -import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import TOML from '@iarna/toml'; -import { AstroError } from 'astro/errors'; -import dotenv from 'dotenv'; -import { Miniflare } from 'miniflare'; - -interface NodeJSError extends Error { - code?: string; -} - -type BASE_RUNTIME = { - mode: 'local'; - type: 'pages' | 'workers'; - persistTo: string; - bindings: Record< - string, - | { type: 'var'; value: string | Json } - | { type: 'kv' } - | { type: 'r2' } - | { - type: 'd1'; - } - | { - type: 'durable-object'; - className: string; - service?: { - name: string; - env?: string; - }; - } - | ({ - type: 'service'; - } & ( - | { - address: string; - protocol?: 'http' | 'https'; - } - | { - service: string; - } - )) - >; -}; - -export type RUNTIME = - | { - mode: BASE_RUNTIME['mode']; - type: 'pages'; - persistTo: BASE_RUNTIME['persistTo']; - bindings: BASE_RUNTIME['bindings']; - } - | { - mode: BASE_RUNTIME['mode']; - type: 'workers'; - persistTo: BASE_RUNTIME['persistTo']; - }; - -class LocalRuntime { - private _astroConfig: AstroConfig; - private _logger: AstroIntegrationLogger; - private _miniflare: Miniflare; - - private miniflareBindings: - | Record< - string, - | D1Database - | ReplaceWorkersTypes - | ReplaceWorkersTypes - | ReplaceWorkersTypes - | Json - > - | undefined; - private secrets: Record | undefined; - private cfObject: IncomingRequestCfProperties | undefined; - - public constructor( - astroConfig: AstroConfig, - runtimeConfig: BASE_RUNTIME, - logger: AstroIntegrationLogger - ) { - this._astroConfig = astroConfig; - this._logger = logger; - - const varBindings: Required>['bindings'] = {}; - const kvBindings: Required>['kvNamespaces'] = []; - const d1Bindings: Required>['d1Databases'] = []; - const r2Bindings: Required>['r2Buckets'] = []; - const durableObjectBindings: Required>['durableObjects'] = - {}; - const serviceBindings: Required>['serviceBindings'] = {}; - - for (const bindingName in runtimeConfig.bindings) { - const bindingData = runtimeConfig.bindings[bindingName]; - switch (bindingData.type) { - case 'var': - varBindings[bindingName] = bindingData.value; - break; - case 'kv': - kvBindings.push(bindingName); - break; - case 'd1': - d1Bindings.push(bindingName); - break; - case 'r2': - r2Bindings.push(bindingName); - break; - case 'durable-object': - durableObjectBindings[bindingName] = { - className: bindingData.className, - scriptName: bindingData.service?.name, - }; - break; - case 'service': - if ('address' in bindingData) { - // Pages mode - const isHttps = bindingData.protocol === 'https'; - - const serviceBindingConfig: ExternalServer = isHttps - ? { address: bindingData.address, https: {} } - : { address: bindingData.address, http: {} }; - - serviceBindings[bindingName] = { - external: serviceBindingConfig, - }; - } else if ('service' in bindingData) { - // Worker mode - serviceBindings[bindingName] = bindingData.service; - } - break; - } - } - - this._miniflare = new Miniflare({ - cachePersist: `${runtimeConfig.persistTo}/cache`, - d1Persist: `${runtimeConfig.persistTo}/d1`, - r2Persist: `${runtimeConfig.persistTo}/r2`, - kvPersist: `${runtimeConfig.persistTo}/kv`, - durableObjectsPersist: `${runtimeConfig.persistTo}/do`, - workers: [ - { - name: 'worker', - script: '', - modules: true, - cacheWarnUsage: true, - cache: true, - bindings: varBindings, - d1Databases: d1Bindings, - r2Buckets: r2Bindings, - kvNamespaces: kvBindings, - durableObjects: durableObjectBindings, - serviceBindings: serviceBindings, - }, - ], - }); - } - - public async getBindings() { - await this._miniflare.ready; - if (!this.miniflareBindings) { - this.miniflareBindings = await this._miniflare.getBindings(); - } - return this.miniflareBindings; - } - - public async getSecrets() { - await this._miniflare.ready; - if (!this.secrets) { - try { - this.secrets = dotenv.parse( - readFileSync(fileURLToPath(new URL('./.dev.vars', this._astroConfig.root))) - ); - } catch (error) { - const e = error as NodeJSError; - if (e.code === 'ENOENT') { - this._logger.info( - 'There is no `.dev.vars` file in the root directory, if you have encrypted secrets or environmental variables you Cloudflare recommends to put them in this file' - ); - this.secrets = {}; - } else { - throw new AstroError('Failed to load secrets file', e.message); - } - } - } - return this.secrets; - } - - public async getCaches() { - await this._miniflare.ready; - return this._miniflare.getCaches(); - } - - public async getCF() { - await this._miniflare.ready; - - const MAX_CACHE_AGE = 1000 * 60 * 60 * 24 * 7; // 7 days; - // Try load cached cfObject, if this fails, we'll catch the error and refetch. - // If this succeeds, and the file is stale, that's fine: it's very likely - // we'll be fetching the same data anyways. - try { - const cachedCFObject = JSON.parse( - readFileSync(fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir)), 'utf8') - ); - const cfObjectStats = statSync(fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir))); - assert(Date.now() - cfObjectStats.mtimeMs <= MAX_CACHE_AGE); - this.cfObject = cachedCFObject; - } catch {} - - const CF_ENDPOINT = 'https://workers.cloudflare.com/cf.json'; - if (!this.cfObject) { - this.cfObject = await fetch(CF_ENDPOINT).then((res) => res.json()); - if (!existsSync(this._astroConfig.cacheDir)) { - mkdirSync(this._astroConfig.cacheDir); - } - writeFileSync( - fileURLToPath(new URL('cf.json', this._astroConfig.cacheDir)), - JSON.stringify(this.cfObject), - 'utf8' - ); - } - return this.cfObject; - } - - public async dispose() { - await this._miniflare.dispose(); - } -} - -export class LocalWorkersRuntime extends LocalRuntime { - constructor( - astroConfig: AstroConfig, - runtimeConfig: Extract, - logger: AstroIntegrationLogger - ) { - let _wranglerConfig: CF_RawConfig | undefined; - try { - _wranglerConfig = TOML.parse( - readFileSync(fileURLToPath(new URL('./wrangler.toml', astroConfig.root)), 'utf-8').replace( - /\r\n/g, - '\n' - ) - ) as unknown as CF_RawConfig; - } catch (error) { - const e = error as NodeJSError; - if (e.code === 'ENOENT') { - logger.error('Missing file `wrangler.toml in root directory`'); - } else { - throw new AstroError('Failed to load wrangler config', e.message); - } - } - const runtimeConfigWithWrangler: BASE_RUNTIME = { - ...runtimeConfig, - bindings: {}, - }; - if (_wranglerConfig?.vars) { - for (const key in _wranglerConfig.vars) { - runtimeConfigWithWrangler.bindings[key] = { - type: 'var', - value: _wranglerConfig.vars[key], - }; - } - } - if (_wranglerConfig?.kv_namespaces) { - for (const ns of _wranglerConfig.kv_namespaces) { - runtimeConfigWithWrangler.bindings[ns.binding] = { - type: 'kv', - }; - } - } - if (_wranglerConfig?.d1_databases) { - for (const db of _wranglerConfig.d1_databases) { - runtimeConfigWithWrangler.bindings[db.binding] = { - type: 'd1', - }; - } - } - if (_wranglerConfig?.r2_buckets) { - for (const bucket of _wranglerConfig.r2_buckets) { - runtimeConfigWithWrangler.bindings[bucket.binding] = { - type: 'r2', - }; - } - } - if (_wranglerConfig?.durable_objects) { - for (const durableObject of _wranglerConfig.durable_objects.bindings) { - runtimeConfigWithWrangler.bindings[durableObject.name] = { - type: 'durable-object', - className: durableObject.class_name, - service: durableObject.script_name - ? { - name: durableObject.script_name, - } - : undefined, - }; - } - } - if (_wranglerConfig?.services) { - for (const service of _wranglerConfig.services) { - runtimeConfigWithWrangler.bindings[service.binding] = { - type: 'service', - service: service.service, - }; - } - } - - super(astroConfig, runtimeConfigWithWrangler, logger); - } -} - -export class LocalPagesRuntime extends LocalRuntime { - // biome-ignore lint/complexity/noUselessConstructor: not types information yet, so we need to disable the rule for the time being - public constructor( - astroConfig: AstroConfig, - runtimeConfig: Extract, - logger: AstroIntegrationLogger - ) { - super(astroConfig, runtimeConfig, logger); - } -} - -let localRuntime: LocalPagesRuntime | LocalWorkersRuntime | undefined; -export function getLocalRuntime( - astroConfig: AstroConfig, - runtimeConfig: RUNTIME, - logger: AstroIntegrationLogger -): LocalPagesRuntime | LocalWorkersRuntime { - if (localRuntime) return localRuntime; - - if (runtimeConfig.type === 'pages') { - localRuntime = new LocalPagesRuntime(astroConfig, runtimeConfig, logger); - } else { - localRuntime = new LocalWorkersRuntime(astroConfig, runtimeConfig, logger); - } - - return localRuntime; -} - -export function getRuntimeConfig(userConfig?: Options['runtime']): { mode: 'off' } | RUNTIME { - if (!userConfig || userConfig.mode === 'off') return { mode: 'off' }; - - // we know that we have `mode: local` below - if (userConfig.type === 'pages') - return { - mode: 'local', - type: 'pages', - persistTo: userConfig.persistTo ?? '.wrangler/state/v3', - bindings: userConfig.bindings ?? {}, - }; - - // we know that we have `type: workers` below - return { - mode: 'local', - type: 'workers', - persistTo: userConfig.persistTo ?? '.wrangler/state/v3', - }; -} diff --git a/packages/cloudflare/src/utils/parser.ts b/packages/cloudflare/src/utils/parser.ts deleted file mode 100644 index 0bae2c67..00000000 --- a/packages/cloudflare/src/utils/parser.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * This file is a derivative work of wrangler by Cloudflare - * An upstream request for exposing this API was made here: - * https://github.com/cloudflare/workers-sdk/issues/3897 - * - * Until further notice, we will be using this file as a workaround - * TODO: Tackle this file, once their is an decision on the upstream request - */ - -import * as fs from 'node:fs'; -import { dirname, resolve } from 'node:path'; -import type {} from '@cloudflare/workers-types/experimental'; -import TOML from '@iarna/toml'; -import dotenv from 'dotenv'; -import { findUpSync } from 'find-up'; -let _wrangler: any; - -function findWranglerToml( - referencePath: string = process.cwd(), - preferJson = false -): string | undefined { - if (preferJson) { - return ( - findUpSync('wrangler.json', { cwd: referencePath }) ?? - findUpSync('wrangler.toml', { cwd: referencePath }) - ); - } - return findUpSync('wrangler.toml', { cwd: referencePath }); -} -type File = { - file?: string; - fileText?: string; -}; -type Location = File & { - line: number; - column: number; - length?: number; - lineText?: string; - suggestion?: string; -}; -type Message = { - text: string; - location?: Location; - notes?: Message[]; - kind?: 'warning' | 'error'; -}; -class ParseError extends Error implements Message { - readonly text: string; - readonly notes: Message[]; - readonly location?: Location; - readonly kind: 'warning' | 'error'; - - constructor({ text, notes, location, kind }: Message) { - super(text); - this.name = this.constructor.name; - this.text = text; - this.notes = notes ?? []; - this.location = location; - this.kind = kind ?? 'error'; - } -} -const TOML_ERROR_NAME = 'TomlError'; -const TOML_ERROR_SUFFIX = ' at row '; -type TomlError = Error & { - line: number; - col: number; -}; -function parseTOML(input: string, file?: string): TOML.JsonMap | never { - try { - // Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33. - const normalizedInput = input.replace(/\r\n/g, '\n'); - return TOML.parse(normalizedInput); - } catch (err) { - const { name, message, line, col } = err as TomlError; - if (name !== TOML_ERROR_NAME) { - throw err; - } - const text = message.substring(0, message.lastIndexOf(TOML_ERROR_SUFFIX)); - const lineText = input.split('\n')[line]; - const location = { - lineText, - line: line + 1, - column: col - 1, - file, - fileText: input, - }; - throw new ParseError({ text, location }); - } -} - -export interface DotEnv { - path: string; - parsed: dotenv.DotenvParseOutput; -} -function tryLoadDotEnv(path: string): DotEnv | undefined { - try { - const parsed = dotenv.parse(fs.readFileSync(path)); - return { path, parsed }; - } catch (e) { - // logger.debug(`Failed to load .env file "${path}":`, e); - } -} -/** - * Loads a dotenv file from , preferring to read . if - * is defined and that file exists. - */ - -export function loadDotEnv(path: string): DotEnv | undefined { - return tryLoadDotEnv(path); -} -function getVarsForDev(config: any, configPath: string | undefined): any { - const configDir = resolve(dirname(configPath ?? '.')); - const devVarsPath = resolve(configDir, '.dev.vars'); - const loaded = loadDotEnv(devVarsPath); - if (loaded !== undefined) { - return { - ...config.vars, - ...loaded.parsed, - }; - } - return config.vars; -} - -function parseConfig() { - if (_wrangler) return _wrangler; - // biome-ignore lint/suspicious/noImplicitAnyLet: correct usage - let rawConfig; - const configPath = findWranglerToml(process.cwd(), false); // false = args.experimentalJsonConfig - if (!configPath) { - throw new Error('Could not find wrangler.toml'); - } - // Load the configuration from disk if available - if (configPath?.endsWith('toml')) { - rawConfig = parseTOML(fs.readFileSync(configPath).toString(), configPath); - } - _wrangler = { rawConfig, configPath }; - return { rawConfig, configPath }; -} - -export async function getEnvVars() { - const { rawConfig, configPath } = parseConfig(); - const vars = getVarsForDev(rawConfig, configPath); - return vars; -} - -export async function getD1Bindings() { - const { rawConfig } = parseConfig(); - if (!rawConfig) return []; - if (!rawConfig?.d1_databases) return []; - const bindings = (rawConfig?.d1_databases as []).map( - (binding: { binding: string }) => binding.binding - ); - return bindings; -} - -export async function getR2Bindings() { - const { rawConfig } = parseConfig(); - if (!rawConfig) return []; - if (!rawConfig?.r2_buckets) return []; - const bindings = (rawConfig?.r2_buckets as []).map( - (binding: { binding: string }) => binding.binding - ); - return bindings; -} - -export async function getKVBindings() { - const { rawConfig } = parseConfig(); - if (!rawConfig) return []; - if (!rawConfig?.kv_namespaces) return []; - const bindings = (rawConfig?.kv_namespaces as []).map( - (binding: { binding: string }) => binding.binding - ); - return bindings; -} - -export function getDOBindings(): Record< - string, - { scriptName?: string | undefined; unsafeUniqueKey?: string | undefined; className: string } -> { - const { rawConfig } = parseConfig(); - if (!rawConfig) return {}; - if (!rawConfig.durable_objects) return {}; - const output = new Object({}) as Record< - string, - { scriptName?: string | undefined; unsafeUniqueKey?: string | undefined; className: string } - >; - const bindings = rawConfig.durable_objects.bindings; - for (const binding of bindings) { - Reflect.set(output, binding.name, { className: binding.class_name }); - } - return output; -}