everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 25.1 kB
Source Map (JSON)
{"version":3,"file":"resolver.cjs","names":["Schema","path","Context","Layer","Effect","readFile","cacheControlOf","Data","Duration","Cause","Schedule","FetchNetworkError","ManagedRuntime","HttpFetch","bundleCachePath","readBundleCache","writeBundleCache","isAppDescriptorPath","readFileSync","existsSync"],"sources":["../../../src/services/resolution/resolver.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n Cause,\n Context,\n Data,\n Duration,\n Effect,\n Layer,\n ManagedRuntime,\n Schedule,\n Schema,\n} from \"effect\";\nimport { cacheControlOf } from \"every-plugin/build/artifact-names\";\nimport { isAppDescriptorPath } from \"../../config\";\nimport { FetchNetworkError, HttpFetch, type HttpFetchShape } from \"../../utils/http-client\";\nimport { bundleCachePath, readBundleCache, writeBundleCache } from \"../registry/bundle-cache\";\n\ntype FetchImpl = typeof globalThis.fetch;\n\n/**\n * Bundle resolution — the one seam every boot-time byte crosses (config\n * manifest discovery, contract-type fetches, federation remote loading, SSR\n * serving). Two tiers, one policy (ADR 0011/0021):\n *\n * - Self-contained runtime image: a staged namespace under `BOS_BUNDLE_DIR`\n * resolves from disk; a miss falls through to the network so a partially-\n * staged namespace boots over the wire instead of failing.\n * - Registry tier: plain resilient network fetch — CDN is the single\n * distribution source. The stale-if-error disk cache exists only behind an\n * explicit `BOS_BUNDLE_CACHE_DIR` opt-in; cached bytes are a resilience\n * artifact, never a deployment, so a post-reset boot can never satisfy\n * itself with pre-reset bytes.\n */\n\nexport interface BundleNamespace {\n readonly bundleDir: string;\n readonly account: string;\n readonly gateway: string;\n}\n\nexport class BundleReadError extends Schema.TaggedError<BundleReadError>()(\"BundleReadError\", {\n path: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n}) {}\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"text/javascript\",\n \".mjs\": \"text/javascript\",\n \".cjs\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".map\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".html\": \"text/html\",\n \".htm\": \"text/html\",\n \".webmanifest\": \"application/manifest+json\",\n \".md\": \"text/markdown\",\n \".ts\": \"text/plain\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n \".eot\": \"application/vnd.ms-opentype\",\n \".wasm\": \"application/wasm\",\n \".txt\": \"text/xml\",\n \".xml\": \"application/xml\",\n};\n\n/**\n * Maps a bundle URL onto the staged namespace layout. Bundle URLs carry their\n * namespace in the path (`…/bundles/<account>/<gateway>/<workspace>/…`); the\n * staged layout mirrors it under `<bundleDir>/<account>/<gateway>/…`. The\n * namespace is taken from the URL itself — this answers \"which staged\n * directory do these bytes live in?\" rather than \"is this my namespace?\" —\n * and the result is contained within the account/gateway directory. Returns\n * null for foreign shapes.\n */\nexport function bundleUrlToStagedPath(url: string, bundleDir: string): string | null {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return null;\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return null;\n\n const segments = parsed.pathname.split(\"/\").filter(Boolean);\n if (segments[0] !== \"bundles\" || segments.length < 3) return null;\n\n let decoded: string[];\n try {\n decoded = segments.slice(1).map((segment) => decodeURIComponent(segment));\n } catch {\n return null;\n }\n const [account, gateway, ...rest] = decoded;\n if (!account || !gateway || rest.length === 0) return null;\n\n const nsDir = path.resolve(bundleDir, account, gateway);\n const filePath = path.resolve(nsDir, ...rest);\n if (filePath === nsDir || !filePath.startsWith(nsDir + path.sep)) return null;\n return filePath;\n}\n\n/** Resolve a relative config-supplied path inside `dir`, or null on escape. */\nexport function resolveContained(dir: string, relative: string): string | null {\n const resolved = path.resolve(dir, ...relative.split(\"/\").filter(Boolean));\n if (resolved === dir || !resolved.startsWith(dir + path.sep)) return null;\n return resolved;\n}\n\n/**\n * Own-namespace path for a bundle URL: the shared URL→staged-path mapping,\n * narrowed to the runtime identity — a URL whose encoded namespace differs\n * from `namespace.account`/`namespace.gateway` must fall to the network,\n * never serve a sibling namespace's staged bytes.\n */\nexport function bundleUrlToLocalPath(url: string, namespace: BundleNamespace): string | null {\n const filePath = bundleUrlToStagedPath(url, namespace.bundleDir);\n if (!filePath) return null;\n\n const nsDir = path.resolve(namespace.bundleDir, namespace.account, namespace.gateway);\n if (filePath !== nsDir && !filePath.startsWith(nsDir + path.sep)) return null;\n\n return filePath;\n}\n\nexport class BundleResolver extends Context.Service<\n BundleResolver,\n {\n /** Resolve a fetch target from the staged namespace; null = miss or not our namespace — fall through to the network. */\n readonly lookup: (input: string | URL | Request) => Effect.Effect<Response | null>;\n }\n>()(\"everything-dev/resolver/BundleResolver\") {\n static layer(namespace: BundleNamespace | undefined): Layer.Layer<BundleResolver> {\n if (!namespace) {\n return Layer.succeed(\n BundleResolver,\n BundleResolver.of({ lookup: () => Effect.succeed(null) }),\n );\n }\n const respond = Effect.fn(\"BundleResolver.respond\")(function* (\n url: string,\n ): Effect.fn.Return<Response | null, never> {\n const filePath = bundleUrlToLocalPath(url, namespace);\n if (!filePath) return null;\n const bytes = yield* Effect.tryPromise({\n try: () => readFile(filePath),\n catch: (cause) => new BundleReadError({ path: filePath, cause }),\n }).pipe(Effect.catchTag(\"BundleReadError\", () => Effect.succeed(null)));\n if (bytes === null) return null;\n const name = path.basename(filePath);\n const contentType =\n MIME_TYPES[path.extname(name).toLowerCase()] ?? \"application/octet-stream\";\n return new Response(new Uint8Array(bytes), {\n headers: {\n \"content-type\": contentType,\n \"cache-control\": cacheControlOf(name),\n etag: `\"${Buffer.from(bytes.subarray(0, 4096)).toString(\"base64\").slice(0, 24)}\"`,\n },\n });\n });\n\n return Layer.effect(\n BundleResolver,\n Effect.succeed(\n BundleResolver.of({\n lookup: (input) => {\n const url =\n typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n return respond(url);\n },\n }),\n ),\n );\n }\n}\n\nexport interface BundleFetchHandle {\n readonly uninstall: () => Promise<void>;\n}\n\nexport interface BundleFetchOptions {\n /** Own-namespace FS resolution — requires a staged `BOS_BUNDLE_DIR`. */\n namespace?: BundleNamespace;\n /**\n * Explicit opt-in stale-if-error cache (child tier): `/bundles/…` URLs\n * write through to disk on success and serve last-known-good bytes when\n * the origin fails. Never derived implicitly — a cache that activates\n * itself can serve pre-reset bytes after a deploy.\n */\n cacheDir?: string;\n /** Per-attempt deadline for idempotent GETs crossing the interceptor. */\n timeoutMs?: number;\n}\n\nconst staleResponse = (bytes: Uint8Array, url: string): Response => {\n const name = url.split(\"?\")[0]?.split(\"/\").pop() ?? \"\";\n const contentType = MIME_TYPES[path.extname(name).toLowerCase()] ?? \"application/octet-stream\";\n return new Response(bytes.slice().buffer, {\n status: 200,\n headers: { \"content-type\": contentType, \"x-bundle-cache\": \"stale\" },\n });\n};\n\nconst DEFAULT_ATTEMPT_TIMEOUT = \"30 seconds\";\nconst RETRY_BASE_DELAY = \"250 millis\";\nconst RETRY_CAP = \"5 seconds\";\nconst RETRY_TIMES = 4;\n\nconst isTransientStatus = (status: number): boolean => status === 429 || status >= 500;\n\nfunction requestMethod(input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"string\" || input instanceof URL) return \"GET\";\n return input.method.toUpperCase();\n}\n\nconst asError = (cause: unknown): Error =>\n cause instanceof Error ? cause : new Error(String(cause));\n\n/** A 429/5xx response — carried as a failure so the Schedule can retry it,\n * with the Response kept for the exhausted-retries fallthrough. */\nclass TransientBundleResponse extends Data.TaggedError(\"TransientBundleResponse\")<{\n readonly response: Response;\n}> {}\n\n/**\n * One network attempt through the `HttpFetch` policy: the fetch runs under\n * the fiber's interruption signal, and `Effect.timeout` interrupts at the\n * deadline — aborting the in-flight request. The response is returned\n * regardless of status; transient statuses are lifted by the caller.\n */\nconst fetchAttempt = Effect.fn(\"resolver.attempt\")(function* (\n http: HttpFetchShape,\n input: Parameters<FetchImpl>[0],\n init: Parameters<FetchImpl>[1],\n timeout: Duration.Duration,\n): Effect.fn.Return<Response, FetchNetworkError | Cause.TimeoutError | TransientBundleResponse> {\n return yield* http.attempt(input, init).pipe(\n Effect.timeoutOrElse({\n duration: Duration.toMillis(timeout),\n orElse: () => Effect.fail(new Cause.TimeoutError()),\n }),\n Effect.filterOrFail(\n (response) => !isTransientStatus(response.status),\n (response) => new TransientBundleResponse({ response }),\n ),\n );\n});\n\n/**\n * The resilience policy for idempotent GETs crossing the interceptor\n * (ADR 0021 amendment — the CDN-only image): a cold boot has no staged\n * fallback, so one edge hiccup or a hung connection during the load window\n * must not hard-fail the host or a plugin. Transient statuses and network\n * errors (including the deadline's TimeoutError) retry on a capped\n * exponential schedule before propagating; the last transient response is\n * returned so an explicit stale-if-error cache still sees it. Non-GETs pass\n * through untouched; a caller-initiated cancellation is never spent on the\n * schedule.\n */\nconst resilientFetch = Effect.fn(\"resolver.fetch\")(function* (\n http: HttpFetchShape,\n input: Parameters<FetchImpl>[0],\n init: Parameters<FetchImpl>[1],\n timeout: Duration.Duration,\n): Effect.fn.Return<Response, Cause.TimeoutError | Error> {\n if (requestMethod(input, init) !== \"GET\") {\n return yield* http.attempt(input, init).pipe(Effect.mapError((cause) => asError(cause.cause)));\n }\n return yield* fetchAttempt(http, input, init, timeout).pipe(\n Effect.retry({\n schedule: Schedule.exponential(RETRY_BASE_DELAY).pipe(\n Schedule.upTo({ duration: RETRY_CAP, times: RETRY_TIMES }),\n ),\n // A caller-initiated cancellation is not transient — propagate it\n // immediately instead of spending the schedule on a canceled request.\n while: (error) =>\n !(\n (error instanceof FetchNetworkError || error instanceof Cause.TimeoutError) &&\n init?.signal?.aborted\n ),\n }),\n Effect.catchTags({\n TransientBundleResponse: (error) => Effect.succeed(error.response),\n FetchNetworkError: (error) => Effect.fail(asError(error.cause)),\n }),\n );\n});\n\n/**\n * Installs the resolver as a global fetch interceptor — the one seam every\n * boot-time consumer shares (config manifest discovery, contract-type\n * fetches, orchestrator host loading, MF remoteEntry/identity probes) and\n * the SSR serving path. One layered resolution policy, as a single Effect\n * program on the managed runtime: staged disk → network → (explicitly\n * opted-in) stale-if-error. Own-namespace URLs resolve from the staged\n * directory and fall through to the network on a miss; a miss never touches\n * the write-through cache — for the own namespace the staged disk IS the\n * resilience artifact. Inert when neither a staged namespace nor an\n * explicit cache is configured.\n */\nexport function installGlobalBundleFetch(options: BundleFetchOptions): BundleFetchHandle {\n const namespace = options.namespace;\n const cacheDir = options.cacheDir;\n const timeout = Duration.millis(options.timeoutMs ?? Duration.toMillis(DEFAULT_ATTEMPT_TIMEOUT));\n const original: FetchImpl = globalThis.fetch;\n\n const runtime = ManagedRuntime.make(\n Layer.mergeAll(BundleResolver.layer(namespace), HttpFetch.layerWith({ fetchImpl: original })),\n );\n\n const program = Effect.fn(\"resolver.program\")(function* (\n input: Parameters<FetchImpl>[0],\n init?: Parameters<FetchImpl>[1],\n ): Effect.fn.Return<Response, Cause.TimeoutError | Error, BundleResolver | HttpFetch> {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const http = yield* HttpFetch;\n\n if (namespace && bundleUrlToLocalPath(url, namespace)) {\n const resolver = yield* BundleResolver;\n const local = yield* resolver.lookup(input);\n if (local !== null) return local;\n return yield* resilientFetch(http, input, init, timeout);\n }\n\n if (cacheDir !== undefined && bundleCachePath(url, { cacheDir })) {\n const cachedRead = Effect.tryPromise(() => readBundleCache(url, { cacheDir }));\n return yield* Effect.gen(function* () {\n const response = yield* resilientFetch(http, input, init, timeout);\n if (response.ok) {\n // write-through is best-effort\n yield* Effect.tryPromise(async () => {\n const bytes = new Uint8Array(await response.clone().arrayBuffer());\n await writeBundleCache(url, bytes, { cacheDir });\n }).pipe(Effect.ignore);\n } else {\n const cached = yield* cachedRead;\n if (cached) return staleResponse(cached, url);\n }\n return response;\n }).pipe(\n Effect.catch((error) =>\n Effect.gen(function* () {\n const cached = yield* cachedRead;\n if (cached) return staleResponse(cached, url);\n return yield* Effect.fail(error);\n }),\n ),\n );\n }\n\n return yield* resilientFetch(http, input, init, timeout);\n });\n\n interface FetchWithPreconnect {\n (input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]): Promise<Response>;\n preconnect?: (...args: unknown[]) => unknown;\n }\n\n const patched = ((input: Parameters<FetchImpl>[0], init?: Parameters<FetchImpl>[1]) =>\n runtime.runPromise(program(input, init))) as FetchWithPreconnect;\n const originalPreconnect = (original as FetchWithPreconnect).preconnect;\n if (originalPreconnect) {\n patched.preconnect = originalPreconnect.bind(original);\n }\n globalThis.fetch = patched as unknown as FetchImpl;\n return {\n uninstall: async () => {\n if (globalThis.fetch === patched) {\n globalThis.fetch = original;\n }\n await runtime.dispose();\n },\n };\n}\n\n/**\n * A deployment env that accidentally carries an empty or quoted-empty\n * `BOS_BUNDLE_DIR` (e.g. the literal two characters `\"\"` from a quoting\n * mistake) normalizes to unset — silently, no warning.\n */\nconst normalizeBundleDir = (raw: string | undefined): string | undefined => {\n const trimmed = raw?.trim();\n if (!trimmed) return undefined;\n const unquoted =\n trimmed.length >= 2 &&\n ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")))\n ? trimmed.slice(1, -1).trim()\n : trimmed;\n return unquoted.length > 0 ? unquoted : undefined;\n};\n\n/**\n * Boot-time installer for the CLI and the host server: derives the own\n * namespace from `BOS_BUNDLE_DIR` plus the runtime identity\n * (`BOS_ACCOUNT`/`BOS_GATEWAY` registry env taking precedence over the\n * bos.config.json fields), and the stale-if-error cache from an explicit\n * `BOS_BUNDLE_CACHE_DIR` — never implicit. Tier auto-detection (ADR 0021):\n * an identity whose namespace is not actually staged under the bundle dir\n * drops to the registry tier — plain resilient network fetch — instead of\n * deterministically 404ing own-namespace URLs against a foreign image's\n * staged bytes. Never throws — a missing or malformed identity leaves the\n * default fetch in place.\n */\nexport function installBundleFetchFromEnv(input: {\n configPath?: string | null;\n}): BundleFetchHandle | null {\n const bundleDir = normalizeBundleDir(process.env.BOS_BUNDLE_DIR);\n const cacheDir = process.env.BOS_BUNDLE_CACHE_DIR;\n if (!bundleDir && cacheDir === undefined) return null;\n\n let configAccount: string | undefined;\n let configGateway: string | undefined;\n const configPath = input.configPath;\n if (configPath && !isAppDescriptorPath(configPath)) {\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf8\")) as {\n account?: string;\n domain?: string;\n };\n configAccount = parsed.account;\n configGateway = parsed.domain;\n } catch {\n // unreadable config — identity may still come from the registry env\n }\n }\n\n const account = process.env.BOS_ACCOUNT ?? configAccount;\n const gateway = process.env.BOS_GATEWAY ?? configGateway;\n if (bundleDir && (!account || !gateway)) return null;\n\n let namespace: BundleNamespace | undefined;\n if (bundleDir && account && gateway) {\n if (existsSync(path.join(bundleDir, account, gateway))) {\n namespace = { bundleDir, account, gateway };\n } else {\n console.warn(\n `[bundles] staged namespace ${account}/${gateway} not found under ${JSON.stringify(bundleDir)} — registry tier (network fetch)`,\n );\n }\n }\n return installGlobalBundleFetch({ namespace, cacheDir });\n}\n"],"mappings":"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"}