@astroscope/node 1.3.0 → 2.0.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/README.md +33 -1
- package/dist/boot.d.ts +0 -1
- package/dist/boot.d.ts.map +1 -1
- package/dist/{construct-DgB-jR0a.d.ts → construct-BGlPfWMF.d.ts} +1 -2
- package/dist/construct-BGlPfWMF.d.ts.map +1 -0
- package/dist/csrf-middleware-entrypoint.d.ts.map +1 -1
- package/dist/dev-middleware-entrypoint.d.ts +0 -1
- package/dist/dev-middleware-entrypoint.d.ts.map +1 -1
- package/dist/emitters-C20tjKLp.js +43 -0
- package/dist/emitters-C20tjKLp.js.map +1 -0
- package/dist/{events-CUzQ2_cp.d.ts → events-u7J3ezJR.d.ts} +1 -2
- package/dist/events-u7J3ezJR.d.ts.map +1 -0
- package/dist/{excludes-DLF3A_Cf.d.ts → excludes-BDiE3eyp.d.ts} +1 -2
- package/dist/excludes-BDiE3eyp.d.ts.map +1 -0
- package/dist/excludes.d.ts +1 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/image-endpoint.d.ts +11 -0
- package/dist/image-endpoint.d.ts.map +1 -0
- package/dist/image-endpoint.js +11 -0
- package/dist/image-endpoint.js.map +1 -0
- package/dist/image-service.d.ts +15 -0
- package/dist/image-service.d.ts.map +1 -0
- package/dist/image-service.js +28 -0
- package/dist/image-service.js.map +1 -0
- package/dist/index.d.ts +27 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +280 -7
- package/dist/index.js.map +1 -1
- package/dist/islands-middleware-entrypoint.d.ts +5 -0
- package/dist/islands-middleware-entrypoint.d.ts.map +1 -0
- package/dist/islands-middleware-entrypoint.js +58 -0
- package/dist/islands-middleware-entrypoint.js.map +1 -0
- package/dist/islands-runtime.d.ts +1 -0
- package/dist/islands-runtime.js +113 -0
- package/dist/islands-runtime.js.map +1 -0
- package/dist/islands.d.ts +2 -0
- package/dist/islands.js +3 -0
- package/dist/lifecycle/events.d.ts +1 -1
- package/dist/log/index.d.ts +1 -2
- package/dist/log/index.d.ts.map +1 -1
- package/dist/log-B69HEBvg.js.map +1 -1
- package/dist/native-mount-DjYEnO4X.js.map +1 -1
- package/dist/native.d.ts +0 -1
- package/dist/native.d.ts.map +1 -1
- package/dist/prepare-CXZsyAVk.js.map +1 -1
- package/dist/prerendered-CpEAJN_q.js +34 -0
- package/dist/prerendered-CpEAJN_q.js.map +1 -0
- package/dist/preview.d.ts +0 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/route-middleware-entrypoint.d.ts +0 -1
- package/dist/route-middleware-entrypoint.d.ts.map +1 -1
- package/dist/route-store-DdxGePj2.js +27 -0
- package/dist/route-store-DdxGePj2.js.map +1 -0
- package/dist/route-store-DtY3uvLf.d.ts +69 -0
- package/dist/route-store-DtY3uvLf.d.ts.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +32 -15
- package/dist/server.js.map +1 -1
- package/dist/transform-D8dIBGEr.js +191 -0
- package/dist/transform-D8dIBGEr.js.map +1 -0
- package/dist/types-D0uMBi2M.d.ts.map +1 -1
- package/package.json +31 -11
- package/dist/construct-DgB-jR0a.d.ts.map +0 -1
- package/dist/events-CUzQ2_cp.d.ts.map +0 -1
- package/dist/excludes-DLF3A_Cf.d.ts.map +0 -1
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":["healthServer","server"],"sources":["../src/observability/telemetry/lifecycle.ts","../src/server/client-dir.ts","../src/server/serve-app.ts","../src/server/serve-static.ts","../src/server/server.ts"],"sourcesContent":["import { type Context, type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\nconst LIB_NAME = '@astroscope/node';\n\n/**\n * Lifecycle spans (`startup` / `shutdown` with phase children). No-op when no\n * SDK is registered — `trace.getTracer` returns the no-op tracer.\n */\n\nexport function startLifecycleSpan(name: string, parent?: Context): { span: Span; context: Context } {\n const parentContext = parent ?? context.active();\n const span = trace.getTracer(LIB_NAME).startSpan(name, undefined, parentContext);\n\n return { span, context: trace.setSpan(parentContext, span) };\n}\n\nexport async function withLifecycleSpan<T>(name: string, parent: Context, fn: () => Promise<T> | T): Promise<T> {\n const { span, context: spanContext } = startLifecycleSpan(name, parent);\n\n try {\n const result = await context.with(spanContext, fn);\n\n span.setStatus({ code: SpanStatusCode.OK });\n\n return result;\n } catch (err) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: err instanceof Error ? err.message : 'unknown error' });\n\n throw err;\n } finally {\n span.end();\n }\n}\n","import path from 'node:path';\nimport url from 'node:url';\n\n/**\n * Resolve the client directory at runtime relative to the built server entry.\n *\n * The build-time client/server URLs are only valid on the build machine; in a\n * container the deploy path differs. Walk up from `import.meta.url` of the\n * bundled server code until the server directory is found, then apply the\n * build-time server→client relative path.\n */\nexport function resolveClientDir(options: { client: string; server: string }, importMetaUrl: string): string {\n const clientPath = url.fileURLToPath(new URL(options.client));\n const serverPath = url.fileURLToPath(new URL(options.server));\n const rel = path.relative(serverPath, clientPath);\n const serverFolder = path.basename(serverPath);\n\n let serverEntryFolderURL = path.dirname(importMetaUrl);\n let previous = '';\n\n while (!serverEntryFolderURL.endsWith(serverFolder)) {\n if (serverEntryFolderURL === previous) {\n throw new Error(\n `[@astroscope/node] could not find the server directory \"${serverFolder}\" by walking up from \"${importMetaUrl}\"`,\n );\n }\n\n previous = serverEntryFolderURL;\n serverEntryFolderURL = path.dirname(serverEntryFolderURL);\n }\n\n const clientURL = new URL(rel.endsWith('/') ? rel : `${rel}/`, `${serverEntryFolderURL}/entry.mjs`);\n\n return url.fileURLToPath(clientURL);\n}\n","import { createReadStream } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { BaseApp } from 'astro/app';\nimport { createRequestFromNodeRequest, writeResponse } from 'astro/app/node';\nimport { log } from '../observability/log/index.js';\nimport { getRequestRecord } from '../observability/log/store.js';\nimport type { RuntimeOptions } from '../types.js';\n\nasync function readFSErrorPage(client: string, status: number): Promise<Response | undefined> {\n const filePaths = [`${status}.html`, `${status}/index.html`];\n\n for (const filePath of filePaths) {\n const fullPath = path.join(client, filePath);\n let stream: ReturnType<typeof createReadStream> | undefined;\n\n try {\n stream = createReadStream(fullPath);\n\n await new Promise<void>((resolve, reject) => {\n stream!.once('open', () => resolve());\n stream!.once('error', reject);\n });\n\n return new Response(Readable.toWeb(stream) as ReadableStream, {\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\n });\n } catch {\n stream?.destroy();\n }\n }\n\n return undefined;\n}\n\n/**\n * Render on-demand routes: node req → web Request → `app.render()` → node res.\n * Prerendered pages never reach this handler (the static handler serves them);\n * requests for them landing here render the 404 route.\n */\nexport function createAppHandler(app: BaseApp, options: RuntimeOptions, client: string) {\n process.on('unhandledRejection', (reason) => {\n const requestUrl = getRequestRecord()?.url;\n\n log.error(\n {\n ...(reason instanceof Error ? { err: reason } : { reason }),\n ...(requestUrl && { url: requestUrl }),\n },\n requestUrl ? 'unhandled rejection while rendering' : 'unhandled rejection',\n );\n });\n\n const prerenderedErrorPageFetch = async (url: string): Promise<Response> => {\n const { pathname } = new URL(url);\n\n for (const status of [404, 500]) {\n if (pathname.endsWith(`/${status}.html`) || pathname.endsWith(`/${status}/index.html`)) {\n const response = await readFSErrorPage(client, status);\n\n if (response) return response;\n }\n }\n\n return new Response(null, { status: 404 });\n };\n\n const bodySizeLimit =\n options.bodySizeLimit === 0 || options.bodySizeLimit === Number.POSITIVE_INFINITY\n ? undefined\n : options.bodySizeLimit;\n\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n let request: Request;\n\n try {\n request = createRequestFromNodeRequest(req, {\n allowedDomains: app.getAllowedDomains?.() ?? [],\n ...(bodySizeLimit !== undefined && { bodySizeLimit }),\n port: options.port,\n });\n } catch (err) {\n log.error(err instanceof Error ? { err, url: req.url } : { reason: err, url: req.url }, 'could not render');\n\n res.statusCode = 500;\n res.end('Internal Server Error');\n\n return;\n }\n\n const routeData = app.match(request, true);\n\n const response =\n routeData && !(routeData.type === 'page' && routeData.prerender)\n ? await app.render(request, { addCookieHeader: true, routeData, prerenderedErrorPageFetch })\n : await app.render(request, { addCookieHeader: true, prerenderedErrorPageFetch });\n\n await writeResponse(response, res);\n };\n}\n","import fs from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport path from 'node:path';\nimport type { BaseApp } from 'astro/app';\nimport send from 'send';\nimport { COMPRESSIBLE, MIME_TYPES } from './mime.js';\n\nconst VARIANTS = [\n { encoding: 'br', suffix: '.br' },\n { encoding: 'gzip', suffix: '.gz' },\n] as const;\n\nfunction negotiateVariant(\n req: IncomingMessage,\n client: string,\n pathname: string,\n): { pathname: string; encoding: string } | undefined {\n const accept = req.headers['accept-encoding'];\n\n if (typeof accept !== 'string') return undefined;\n\n for (const { encoding, suffix } of VARIANTS) {\n if (!accept.includes(encoding)) continue;\n\n if (fs.existsSync(path.join(client, `${pathname}${suffix}`))) {\n return { pathname: `${pathname}${suffix}`, encoding };\n }\n }\n\n return undefined;\n}\n\nfunction hasFileExtension(pathname: string): boolean {\n const last = pathname.split('/').pop();\n\n return !!last && last.includes('.');\n}\n\nfunction prependForwardSlash(pathname: string): string {\n return pathname.startsWith('/') ? pathname : `/${pathname}`;\n}\n\nfunction isDirectory(client: string, urlPath: string): boolean {\n const filePath = path.join(client, urlPath);\n const resolved = path.resolve(filePath);\n const resolvedClient = path.resolve(client);\n\n // path traversal guard\n if (resolved !== resolvedClient && !resolved.startsWith(resolvedClient + path.sep)) {\n return false;\n }\n\n try {\n return fs.lstatSync(filePath).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Serve files from the client build directory, falling through to `ssr` when\n * no file matches. Handles trailing-slash redirects per the manifest config\n * and marks hashed assets as immutable.\n */\nexport function createStaticHandler(app: BaseApp, client: string) {\n return (req: IncomingMessage, res: ServerResponse, ssr: () => void): void => {\n if (!req.url) {\n ssr();\n\n return;\n }\n\n let fullUrl = req.url;\n\n if (fullUrl.includes('#')) {\n fullUrl = fullUrl.slice(0, fullUrl.indexOf('#'));\n }\n\n const [urlPath = '', urlQuery] = fullUrl.split('?');\n let fsPath = app.removeBase(urlPath);\n\n try {\n fsPath = decodeURI(fsPath);\n } catch {\n // fall through with the raw path; send() rejects malformed paths itself\n }\n\n const dir = isDirectory(client, fsPath);\n const hasSlash = urlPath.endsWith('/');\n let pathname = urlPath;\n\n switch (app.manifest.trailingSlash) {\n case 'never': {\n if (dir && urlPath !== '/' && hasSlash) {\n res.statusCode = 301;\n res.setHeader('Location', urlPath.slice(0, -1) + (urlQuery ? `?${urlQuery}` : ''));\n res.end();\n\n return;\n }\n\n if (dir && !hasSlash) {\n pathname = `${urlPath}/index.html`;\n }\n\n break;\n }\n case 'ignore': {\n if (dir && !hasSlash) {\n pathname = `${urlPath}/index.html`;\n }\n\n break;\n }\n case 'always': {\n if (!hasSlash && !hasFileExtension(urlPath) && !urlPath.startsWith('/_')) {\n res.statusCode = 301;\n res.setHeader('Location', `${urlPath}/${urlQuery ? `?${urlQuery}` : ''}`);\n res.end();\n\n return;\n }\n\n break;\n }\n }\n\n pathname = prependForwardSlash(app.removeBase(pathname));\n\n const normalizedPathname = path.posix.normalize(pathname);\n const compressible = COMPRESSIBLE.has(path.posix.extname(normalizedPathname));\n const variant = compressible ? negotiateVariant(req, client, normalizedPathname) : undefined;\n\n const stream = send(req, variant?.pathname ?? normalizedPathname, {\n root: client,\n dotfiles: normalizedPathname.startsWith('/.well-known/') ? 'allow' : 'deny',\n // with build.format 'file' or 'preserve', pages are output as `page.html`\n // instead of `page/index.html` — let send() try appending `.html`\n extensions: app.manifest.buildFormat === 'file' || app.manifest.buildFormat === 'preserve' ? ['html'] : [],\n });\n\n let forwardError = false;\n\n stream.on('error', (err: NodeJS.ErrnoException & { statusCode?: number }) => {\n if (forwardError) {\n const status = err.statusCode ?? 500;\n\n if (status >= 500) {\n console.error(err.toString());\n }\n\n res.writeHead(status);\n res.end(status >= 500 ? 'Internal server error' : '');\n\n return;\n }\n\n ssr();\n });\n\n stream.on('file', () => {\n forwardError = true;\n });\n\n // fires before the body and before conditional-GET handling, so these\n // headers also land on 304 responses\n stream.on('headers', (headersRes: ServerResponse) => {\n if (compressible) {\n headersRes.setHeader('Vary', 'Accept-Encoding');\n }\n\n if (variant) {\n headersRes.setHeader('Content-Encoding', variant.encoding);\n headersRes.setHeader(\n 'Content-Type',\n MIME_TYPES.get(path.posix.extname(normalizedPathname)) ?? 'application/octet-stream',\n );\n }\n\n if (normalizedPathname.startsWith(`/${app.manifest.assetsDir}/`)) {\n headersRes.setHeader('Cache-Control', 'public, max-age=31536000, immutable');\n }\n });\n\n stream.pipe(res);\n };\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport https from 'node:https';\nimport { checks, server as healthServer, probes } from '@entwico/health-probes';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createApp } from 'astro/app/entrypoint';\nimport { setGetEnv } from 'astro/env/setup';\n// @ts-expect-error virtual module provided by the integration\nimport { options } from 'virtual:@astroscope/node/config';\nimport { activateHealthChecks, deactivateHealthChecks } from '../health/store.js';\nimport { setBootContext } from '../lifecycle/context.js';\nimport { type BootModule, runShutdown, runStartup } from '../lifecycle/lifecycle.js';\nimport type { BootContext } from '../lifecycle/types.js';\nimport { createRequestInstrumentation } from '../observability/instrument.js';\nimport { dumpEarlyLogs } from '../observability/log/construct.js';\nimport { log } from '../observability/log/index.js';\nimport { startLifecycleSpan, withLifecycleSpan } from '../observability/telemetry/lifecycle.js';\nimport { shutdownTelemetry } from '../observability/telemetry/sdk.js';\nimport { preparePlatform } from '../platform/prepare.js';\nimport type { RuntimeOptions } from '../types.js';\nimport { resolveClientDir } from './client-dir.js';\nimport { clearNativeMounts, dispatchNativeMount } from './native-mount.js';\nimport { createAppHandler } from './serve-app.js';\nimport { createStaticHandler } from './serve-static.js';\n\nsetGetEnv((key) => process.env[key]);\n\nconst runtimeOptions = options as RuntimeOptions;\nconst app = createApp({ streaming: true });\n\nconst roundMs = (n: number) => Math.round(n * 100) / 100;\n\n/**\n * Pre-import every lazily loaded server module (pages, middleware, actions,\n * session driver) so the first request pays no import cost. Uses the\n * manifest's own loaders — exactly what the runtime calls per request.\n */\nasync function warmupModules(): Promise<void> {\n const loaders = [\n ...(app.manifest.pageMap?.values() ?? []),\n app.manifest.middleware,\n app.manifest.actions,\n app.manifest.sessionDriver,\n app.manifest.serverIslandMappings,\n ].filter((load) => load !== undefined);\n\n const results = await Promise.allSettled(loaders.map((load) => load()));\n\n for (const result of results) {\n if (result.status === 'rejected') {\n log.error(\n result.reason instanceof Error ? { err: result.reason } : { reason: result.reason },\n 'warmup import failed',\n );\n }\n }\n}\n\n/**\n * TLS tokens from `SERVER_CERT_PATH` / `SERVER_KEY_PATH` (same contract as\n * `@astrojs/node`). Read after env loading, so the paths may come from `.env`.\n */\nfunction loadTlsOptions(): { cert: Buffer; key: Buffer } | undefined {\n const certPath = process.env['SERVER_CERT_PATH'];\n const keyPath = process.env['SERVER_KEY_PATH'];\n\n if (!certPath && !keyPath) return undefined;\n\n if (!certPath || !keyPath) {\n throw new Error('SERVER_CERT_PATH and SERVER_KEY_PATH must both be set to serve HTTPS');\n }\n\n return { cert: fs.readFileSync(certPath), key: fs.readFileSync(keyPath) };\n}\n\nexport interface ServerHandle {\n host: string;\n port: number;\n stop(): Promise<void>;\n closed(): Promise<void>;\n}\n\nexport async function startServer(overrides?: {\n host?: string | undefined;\n port?: number | undefined;\n}): Promise<ServerHandle> {\n const startedAt = performance.now();\n const host = overrides?.host ?? process.env['HOST'] ?? runtimeOptions.host;\n const port = overrides?.port ?? (process.env['PORT'] ? Number(process.env['PORT']) : runtimeOptions.port);\n const context: BootContext = { dev: false, host, port };\n const health = runtimeOptions.health;\n\n setBootContext(context);\n\n try {\n await preparePlatform({\n dev: false,\n telemetry: runtimeOptions.telemetry ? { prometheus: runtimeOptions.telemetry.prometheus } : false,\n seams: {\n config: () => import('virtual:@astroscope/node/config-entry'),\n instrumentation: () => import('virtual:@astroscope/node/instrumentation-entry'),\n log: () => import('virtual:@astroscope/node/log-entry'),\n },\n });\n } catch (err) {\n // the logger never came up — no silent phase, dump the buffer and die\n dumpEarlyLogs();\n console.error(err);\n process.exit(1);\n }\n\n if (health) {\n healthServer.start({ ...health, host: health.host ?? process.env['HEALTH_HOST'] ?? '0.0.0.0' });\n probes.live.enable();\n activateHealthChecks(checks);\n log.debug('health probes listening');\n }\n\n const startup = startLifecycleSpan('startup');\n\n log.info({ host, port }, 'starting');\n\n // the boot module graph may read config at import time, so it must only be\n // evaluated after preparePlatform() has loaded env and config\n let bootModule: BootModule = {};\n let bootMs = 0;\n let warmupMs = 0;\n\n // starts in parallel with the boot startup, awaited before listen\n const warmupStartedAt = performance.now();\n const warmupSpan = startLifecycleSpan('warmup', startup.context);\n const warmup = warmupModules().then(() => {\n warmupMs = roundMs(performance.now() - warmupStartedAt);\n warmupSpan.span.end();\n });\n\n const shutdownLifecycle = async (\n shutdownContext?: ReturnType<typeof startLifecycleSpan>['context'],\n ): Promise<void> => {\n try {\n if (shutdownContext) {\n await withLifecycleSpan('onShutdown', shutdownContext, () => runShutdown(bootModule, context));\n } else {\n await runShutdown(bootModule, context);\n }\n } catch (err) {\n log.error(err instanceof Error ? { err } : { reason: err }, 'shutdown failed');\n }\n\n clearNativeMounts();\n\n if (health) {\n deactivateHealthChecks();\n await healthServer.stop();\n }\n };\n\n const failStartup = async (err: unknown, message: string): Promise<never> => {\n log.error(err instanceof Error ? { err } : { reason: err }, message);\n startup.span.setStatus({ code: SpanStatusCode.ERROR, message });\n startup.span.end();\n\n await shutdownLifecycle();\n await shutdownTelemetry();\n process.exit(1);\n };\n\n try {\n const bootStartedAt = performance.now();\n\n // @ts-expect-error virtual module provided by the integration\n bootModule = (await import('virtual:@astroscope/node/boot')) as BootModule;\n\n await withLifecycleSpan('boot', startup.context, () => runStartup(bootModule, context));\n\n bootMs = roundMs(performance.now() - bootStartedAt);\n } catch (err) {\n await failStartup(err, 'startup failed');\n }\n\n await warmup;\n\n if (health) probes.startup.enable();\n\n const client = resolveClientDir(runtimeOptions, import.meta.url);\n const appHandler = createAppHandler(app, runtimeOptions, client);\n const staticHandler = createStaticHandler(app, client);\n const instrument = createRequestInstrumentation({\n logging: runtimeOptions.logging,\n telemetry: runtimeOptions.telemetry ? { exclude: runtimeOptions.telemetry.exclude } : false,\n });\n\n let tls: { cert: Buffer; key: Buffer } | undefined;\n\n try {\n tls = loadTlsOptions();\n } catch (err) {\n await failStartup(err, 'failed to load TLS options');\n }\n\n const listener: http.RequestListener = (req, res) => {\n try {\n decodeURI(req.url ?? '');\n } catch {\n res.writeHead(400);\n res.end('Bad request.');\n\n return;\n }\n\n instrument(req, res, () => {\n if (dispatchNativeMount(req, res)) return;\n\n staticHandler(req, res, () => void appHandler(req, res));\n });\n };\n\n const server = tls ? https.createServer(tls, listener) : http.createServer(listener);\n\n try {\n await withLifecycleSpan('listen', startup.context, () => {\n return new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, host, resolve);\n });\n });\n } catch (err) {\n await failStartup(err, `failed to listen on ${host}:${port}`);\n }\n\n if (health) probes.ready.enable();\n\n startup.span.setStatus({ code: SpanStatusCode.OK });\n startup.span.end();\n\n log.info(\n {\n host,\n port,\n ...(tls && { https: true }),\n health: !!health,\n bootMs,\n warmupMs,\n totalMs: roundMs(performance.now() - startedAt),\n },\n 'server ready',\n );\n\n let stopPromise: Promise<void> | undefined;\n let resolveClosed!: () => void;\n\n const closedPromise = new Promise<void>((resolve) => {\n resolveClosed = resolve;\n });\n\n const doStop = async (): Promise<void> => {\n if (health) probes.ready.disable();\n\n log.info('shutdown initiated');\n\n const drainStartedAt = performance.now();\n const shutdown = startLifecycleSpan('shutdown');\n\n await withLifecycleSpan('drain', shutdown.context, async () => {\n const closed = new Promise<void>((resolve) => server.close(() => resolve()));\n\n server.closeIdleConnections();\n\n const forceTimer = setTimeout(() => server.closeAllConnections(), runtimeOptions.shutdownTimeout);\n\n await closed;\n\n clearTimeout(forceTimer);\n });\n\n const drainMs = roundMs(performance.now() - drainStartedAt);\n\n await shutdownLifecycle(shutdown.context);\n\n shutdown.span.end();\n\n log.info({ drainMs }, 'shutdown complete');\n\n await shutdownTelemetry();\n resolveClosed();\n };\n\n const stop = (): Promise<void> => (stopPromise ??= doStop());\n\n process.once('SIGTERM', () => void stop().then(() => process.exit(0)));\n process.once('SIGINT', () => void stop().then(() => process.exit(0)));\n\n return { host, port, stop, closed: () => closedPromise };\n}\n\nif (process.env['ASTROSCOPE_NODE_AUTOSTART'] !== 'disabled') {\n await startServer();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":["healthServer","server"],"sources":["../src/observability/telemetry/lifecycle.ts","../src/server/client-dir.ts","../src/server/serve-app.ts","../src/server/serve-static.ts","../src/server/server.ts"],"sourcesContent":["import { type Context, type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\nconst LIB_NAME = '@astroscope/node';\n\n/**\n * Lifecycle spans (`startup` / `shutdown` with phase children). No-op when no\n * SDK is registered — `trace.getTracer` returns the no-op tracer.\n */\n\nexport function startLifecycleSpan(name: string, parent?: Context): { span: Span; context: Context } {\n const parentContext = parent ?? context.active();\n const span = trace.getTracer(LIB_NAME).startSpan(name, undefined, parentContext);\n\n return { span, context: trace.setSpan(parentContext, span) };\n}\n\nexport async function withLifecycleSpan<T>(name: string, parent: Context, fn: () => Promise<T> | T): Promise<T> {\n const { span, context: spanContext } = startLifecycleSpan(name, parent);\n\n try {\n const result = await context.with(spanContext, fn);\n\n span.setStatus({ code: SpanStatusCode.OK });\n\n return result;\n } catch (err) {\n span.setStatus({ code: SpanStatusCode.ERROR, message: err instanceof Error ? err.message : 'unknown error' });\n\n throw err;\n } finally {\n span.end();\n }\n}\n","import path from 'node:path';\nimport url from 'node:url';\n\n/**\n * Resolve the client directory at runtime relative to the built server entry.\n *\n * The build-time client/server URLs are only valid on the build machine; in a\n * container the deploy path differs. Walk up from `import.meta.url` of the\n * bundled server code until the server directory is found, then apply the\n * build-time server→client relative path.\n */\nexport function resolveClientDir(options: { client: string; server: string }, importMetaUrl: string): string {\n const clientPath = url.fileURLToPath(new URL(options.client));\n const serverPath = url.fileURLToPath(new URL(options.server));\n const rel = path.relative(serverPath, clientPath);\n const serverFolder = path.basename(serverPath);\n\n let serverEntryFolderURL = path.dirname(importMetaUrl);\n let previous = '';\n\n while (!serverEntryFolderURL.endsWith(serverFolder)) {\n if (serverEntryFolderURL === previous) {\n throw new Error(\n `[@astroscope/node] could not find the server directory \"${serverFolder}\" by walking up from \"${importMetaUrl}\"`,\n );\n }\n\n previous = serverEntryFolderURL;\n serverEntryFolderURL = path.dirname(serverEntryFolderURL);\n }\n\n const clientURL = new URL(rel.endsWith('/') ? rel : `${rel}/`, `${serverEntryFolderURL}/entry.mjs`);\n\n return url.fileURLToPath(clientURL);\n}\n","import { createReadStream } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { BaseApp } from 'astro/app';\nimport { createRequestFromNodeRequest, writeResponse } from 'astro/app/node';\nimport { log } from '../observability/log/index.js';\nimport { getRequestRecord } from '../observability/log/store.js';\nimport type { RuntimeOptions } from '../types.js';\nimport { setRequestRouteData } from './route-store.js';\n\nasync function readFSErrorPage(client: string, status: number): Promise<Response | undefined> {\n const filePaths = [`${status}.html`, `${status}/index.html`];\n\n for (const filePath of filePaths) {\n const fullPath = path.join(client, filePath);\n let stream: ReturnType<typeof createReadStream> | undefined;\n\n try {\n stream = createReadStream(fullPath);\n\n await new Promise<void>((resolve, reject) => {\n stream!.once('open', () => resolve());\n stream!.once('error', reject);\n });\n\n return new Response(Readable.toWeb(stream) as ReadableStream, {\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\n });\n } catch {\n stream?.destroy();\n }\n }\n\n return undefined;\n}\n\n/**\n * Render on-demand routes: node req → web Request → `app.render()` → node res.\n * Prerendered pages never reach this handler (the static handler serves them);\n * requests for them landing here render the 404 route.\n */\nexport function createAppHandler(app: BaseApp, options: RuntimeOptions, client: string) {\n process.on('unhandledRejection', (reason) => {\n const requestUrl = getRequestRecord()?.url;\n\n log.error(\n {\n ...(reason instanceof Error ? { err: reason } : { reason }),\n ...(requestUrl && { url: requestUrl }),\n },\n requestUrl ? 'unhandled rejection while rendering' : 'unhandled rejection',\n );\n });\n\n const prerenderedErrorPageFetch = async (url: string): Promise<Response> => {\n const { pathname } = new URL(url);\n\n for (const status of [404, 500]) {\n if (pathname.endsWith(`/${status}.html`) || pathname.endsWith(`/${status}/index.html`)) {\n const response = await readFSErrorPage(client, status);\n\n if (response) return response;\n }\n }\n\n return new Response(null, { status: 404 });\n };\n\n const bodySizeLimit =\n options.bodySizeLimit === 0 || options.bodySizeLimit === Number.POSITIVE_INFINITY\n ? undefined\n : options.bodySizeLimit;\n\n return async (req: IncomingMessage, res: ServerResponse): Promise<void> => {\n let request: Request;\n\n try {\n request = createRequestFromNodeRequest(req, {\n allowedDomains: app.getAllowedDomains?.() ?? [],\n ...(bodySizeLimit !== undefined && { bodySizeLimit }),\n port: options.port,\n });\n } catch (err) {\n log.error(err instanceof Error ? { err, url: req.url } : { reason: err, url: req.url }, 'could not render');\n\n res.statusCode = 500;\n res.end('Internal Server Error');\n\n return;\n }\n\n const routeData = app.match(request, true);\n const matched = routeData && !(routeData.type === 'page' && routeData.prerender) ? routeData : undefined;\n\n if (matched) {\n setRequestRouteData(request, matched);\n }\n\n const response = matched\n ? await app.render(request, { addCookieHeader: true, routeData: matched, prerenderedErrorPageFetch })\n : await app.render(request, { addCookieHeader: true, prerenderedErrorPageFetch });\n\n await writeResponse(response, res);\n };\n}\n","import fs from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport path from 'node:path';\nimport type { BaseApp } from 'astro/app';\nimport send from 'send';\nimport { COMPRESSIBLE, MIME_TYPES } from './mime.js';\n\nconst VARIANTS = [\n { encoding: 'br', suffix: '.br' },\n { encoding: 'gzip', suffix: '.gz' },\n] as const;\n\nfunction negotiateVariant(\n req: IncomingMessage,\n client: string,\n pathname: string,\n): { pathname: string; encoding: string } | undefined {\n const accept = req.headers['accept-encoding'];\n\n if (typeof accept !== 'string') return undefined;\n\n for (const { encoding, suffix } of VARIANTS) {\n if (!accept.includes(encoding)) continue;\n\n if (fs.existsSync(path.join(client, `${pathname}${suffix}`))) {\n return { pathname: `${pathname}${suffix}`, encoding };\n }\n }\n\n return undefined;\n}\n\nfunction hasFileExtension(pathname: string): boolean {\n const last = pathname.split('/').pop();\n\n return !!last && last.includes('.');\n}\n\nfunction prependForwardSlash(pathname: string): string {\n return pathname.startsWith('/') ? pathname : `/${pathname}`;\n}\n\nfunction isDirectory(client: string, urlPath: string): boolean {\n const filePath = path.join(client, urlPath);\n const resolved = path.resolve(filePath);\n const resolvedClient = path.resolve(client);\n\n // path traversal guard\n if (resolved !== resolvedClient && !resolved.startsWith(resolvedClient + path.sep)) {\n return false;\n }\n\n try {\n return fs.lstatSync(filePath).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Serve files from the client build directory, falling through to `ssr` when\n * no file matches. Handles trailing-slash redirects per the manifest config\n * and marks hashed assets as immutable.\n */\nexport function createStaticHandler(app: BaseApp, client: string) {\n return (req: IncomingMessage, res: ServerResponse, ssr: () => void): void => {\n if (!req.url) {\n ssr();\n\n return;\n }\n\n let fullUrl = req.url;\n\n if (fullUrl.includes('#')) {\n fullUrl = fullUrl.slice(0, fullUrl.indexOf('#'));\n }\n\n const [urlPath = '', urlQuery] = fullUrl.split('?');\n let fsPath = app.removeBase(urlPath);\n\n try {\n fsPath = decodeURI(fsPath);\n } catch {\n // fall through with the raw path; send() rejects malformed paths itself\n }\n\n const dir = isDirectory(client, fsPath);\n const hasSlash = urlPath.endsWith('/');\n let pathname = urlPath;\n\n switch (app.manifest.trailingSlash) {\n case 'never': {\n if (dir && urlPath !== '/' && hasSlash) {\n res.statusCode = 301;\n res.setHeader('Location', urlPath.slice(0, -1) + (urlQuery ? `?${urlQuery}` : ''));\n res.end();\n\n return;\n }\n\n if (dir && !hasSlash) {\n pathname = `${urlPath}/index.html`;\n }\n\n break;\n }\n case 'ignore': {\n if (dir && !hasSlash) {\n pathname = `${urlPath}/index.html`;\n }\n\n break;\n }\n case 'always': {\n if (!hasSlash && !hasFileExtension(urlPath) && !urlPath.startsWith('/_')) {\n res.statusCode = 301;\n res.setHeader('Location', `${urlPath}/${urlQuery ? `?${urlQuery}` : ''}`);\n res.end();\n\n return;\n }\n\n break;\n }\n }\n\n pathname = prependForwardSlash(app.removeBase(pathname));\n\n const normalizedPathname = path.posix.normalize(pathname);\n const compressible = COMPRESSIBLE.has(path.posix.extname(normalizedPathname));\n const variant = compressible ? negotiateVariant(req, client, normalizedPathname) : undefined;\n\n const stream = send(req, variant?.pathname ?? normalizedPathname, {\n root: client,\n dotfiles: normalizedPathname.startsWith('/.well-known/') ? 'allow' : 'deny',\n // with build.format 'file' or 'preserve', pages are output as `page.html`\n // instead of `page/index.html` — let send() try appending `.html`\n extensions: app.manifest.buildFormat === 'file' || app.manifest.buildFormat === 'preserve' ? ['html'] : [],\n });\n\n let forwardError = false;\n\n stream.on('error', (err: NodeJS.ErrnoException & { statusCode?: number }) => {\n if (forwardError) {\n const status = err.statusCode ?? 500;\n\n if (status >= 500) {\n console.error(err.toString());\n }\n\n res.writeHead(status);\n res.end(status >= 500 ? 'Internal server error' : '');\n\n return;\n }\n\n ssr();\n });\n\n stream.on('file', () => {\n forwardError = true;\n });\n\n // fires before the body and before conditional-GET handling, so these\n // headers also land on 304 responses\n stream.on('headers', (headersRes: ServerResponse) => {\n if (compressible) {\n headersRes.setHeader('Vary', 'Accept-Encoding');\n }\n\n if (variant) {\n headersRes.setHeader('Content-Encoding', variant.encoding);\n headersRes.setHeader(\n 'Content-Type',\n MIME_TYPES.get(path.posix.extname(normalizedPathname)) ?? 'application/octet-stream',\n );\n }\n\n if (normalizedPathname.startsWith(`/${app.manifest.assetsDir}/`)) {\n headersRes.setHeader('Cache-Control', 'public, max-age=31536000, immutable');\n }\n });\n\n stream.pipe(res);\n };\n}\n","import fs from 'node:fs';\nimport http from 'node:http';\nimport https from 'node:https';\nimport { checks, server as healthServer, probes } from '@entwico/health-probes';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createApp } from 'astro/app/entrypoint';\nimport { setGetEnv } from 'astro/env/setup';\n// @ts-expect-error virtual module provided by the integration\nimport { options } from 'virtual:@astroscope/node/config';\nimport { activateHealthChecks, deactivateHealthChecks } from '../health/store.js';\nimport { setBootContext } from '../lifecycle/context.js';\nimport { type BootModule, runShutdown, runStartup } from '../lifecycle/lifecycle.js';\nimport type { BootContext } from '../lifecycle/types.js';\nimport { createRequestInstrumentation } from '../observability/instrument.js';\nimport { dumpEarlyLogs } from '../observability/log/construct.js';\nimport { log } from '../observability/log/index.js';\nimport { startLifecycleSpan, withLifecycleSpan } from '../observability/telemetry/lifecycle.js';\nimport { shutdownTelemetry } from '../observability/telemetry/sdk.js';\nimport { preparePlatform } from '../platform/prepare.js';\nimport type { RuntimeOptions } from '../types.js';\nimport { resolveClientDir } from './client-dir.js';\nimport { clearNativeMounts, dispatchNativeMount } from './native-mount.js';\nimport { createAppHandler } from './serve-app.js';\nimport { createStaticHandler } from './serve-static.js';\n\nsetGetEnv((key) => process.env[key]);\n\nconst runtimeOptions = options as RuntimeOptions;\nconst app = createApp({ streaming: true });\n\nconst roundMs = (n: number) => Math.round(n * 100) / 100;\n\n/**\n * Pre-import every lazily loaded server module (pages, middleware, actions,\n * session driver) so the first request pays no import cost. Uses the\n * manifest's own loaders — exactly what the runtime calls per request.\n */\nasync function warmupModules(): Promise<void> {\n const loaders = [\n ...(app.manifest.pageMap?.values() ?? []),\n app.manifest.middleware,\n app.manifest.actions,\n app.manifest.sessionDriver,\n app.manifest.serverIslandMappings,\n ].filter((load) => load !== undefined);\n\n const results = await Promise.allSettled(loaders.map((load) => load()));\n const failures = results.filter((result) => result.status === 'rejected');\n\n if (failures.length === 0) return;\n\n for (const failure of failures) {\n log.error(\n failure.reason instanceof Error ? { err: failure.reason } : { reason: failure.reason },\n 'warmup import failed',\n );\n }\n\n // a module that cannot even be imported would throw on its first request;\n // failing the boot turns a silently-degraded deploy into a crash the health\n // checks catch before it takes traffic\n throw new AggregateError(\n failures.map((failure) => failure.reason),\n 'warmup import failed',\n );\n}\n\n/**\n * TLS tokens from `SERVER_CERT_PATH` / `SERVER_KEY_PATH` (same contract as\n * `@astrojs/node`). Read after env loading, so the paths may come from `.env`.\n */\nfunction loadTlsOptions(): { cert: Buffer; key: Buffer } | undefined {\n const certPath = process.env['SERVER_CERT_PATH'];\n const keyPath = process.env['SERVER_KEY_PATH'];\n\n if (!certPath && !keyPath) return undefined;\n\n if (!certPath || !keyPath) {\n throw new Error('SERVER_CERT_PATH and SERVER_KEY_PATH must both be set to serve HTTPS');\n }\n\n return { cert: fs.readFileSync(certPath), key: fs.readFileSync(keyPath) };\n}\n\nexport interface ServerHandle {\n host: string;\n port: number;\n stop(): Promise<void>;\n closed(): Promise<void>;\n}\n\nexport async function startServer(overrides?: {\n host?: string | undefined;\n port?: number | undefined;\n}): Promise<ServerHandle> {\n const startedAt = performance.now();\n const host = overrides?.host ?? process.env['HOST'] ?? runtimeOptions.host;\n const port = overrides?.port ?? (process.env['PORT'] ? Number(process.env['PORT']) : runtimeOptions.port);\n const context: BootContext = { dev: false, host, port };\n const health = runtimeOptions.health;\n\n setBootContext(context);\n\n try {\n await preparePlatform({\n dev: false,\n telemetry: runtimeOptions.telemetry ? { prometheus: runtimeOptions.telemetry.prometheus } : false,\n seams: {\n config: () => import('virtual:@astroscope/node/config-entry'),\n instrumentation: () => import('virtual:@astroscope/node/instrumentation-entry'),\n log: () => import('virtual:@astroscope/node/log-entry'),\n },\n });\n } catch (err) {\n // the logger never came up — no silent phase, dump the buffer and die\n dumpEarlyLogs();\n console.error(err);\n process.exit(1);\n }\n\n if (health) {\n healthServer.start({ ...health, host: health.host ?? process.env['HEALTH_HOST'] ?? '0.0.0.0' });\n probes.live.enable();\n activateHealthChecks(checks);\n log.debug('health probes listening');\n }\n\n const startup = startLifecycleSpan('startup');\n\n log.info({ host, port }, 'starting');\n\n // the boot module graph may read config at import time, so it must only be\n // evaluated after preparePlatform() has loaded env and config\n let bootModule: BootModule = {};\n let bootMs = 0;\n let warmupMs = 0;\n\n // starts in parallel with the boot startup, awaited before listen. resolves\n // to the failure (if any) instead of rejecting, so a warmup error landing\n // before the join below is never seen as an unhandled rejection\n const warmupStartedAt = performance.now();\n const warmupSpan = startLifecycleSpan('warmup', startup.context);\n const warmup = warmupModules().then(\n () => {\n warmupMs = roundMs(performance.now() - warmupStartedAt);\n warmupSpan.span.end();\n\n return undefined;\n },\n (error: unknown) => {\n warmupMs = roundMs(performance.now() - warmupStartedAt);\n warmupSpan.span.setStatus({ code: SpanStatusCode.ERROR, message: 'warmup import failed' });\n warmupSpan.span.end();\n\n return error;\n },\n );\n\n const shutdownLifecycle = async (\n shutdownContext?: ReturnType<typeof startLifecycleSpan>['context'],\n ): Promise<void> => {\n try {\n if (shutdownContext) {\n await withLifecycleSpan('onShutdown', shutdownContext, () => runShutdown(bootModule, context));\n } else {\n await runShutdown(bootModule, context);\n }\n } catch (err) {\n log.error(err instanceof Error ? { err } : { reason: err }, 'shutdown failed');\n }\n\n clearNativeMounts();\n\n if (health) {\n deactivateHealthChecks();\n\n try {\n await healthServer.stop();\n } catch (err) {\n // a startup failure can tear the health server down before it has\n // finished binding; stopping it is best-effort\n log.debug(err instanceof Error ? { err } : { reason: err }, 'health probe server stop failed');\n }\n }\n };\n\n const failStartup = async (err: unknown, message: string): Promise<never> => {\n log.error(err instanceof Error ? { err } : { reason: err }, message);\n startup.span.setStatus({ code: SpanStatusCode.ERROR, message });\n startup.span.end();\n\n await shutdownLifecycle();\n await shutdownTelemetry();\n process.exit(1);\n };\n\n try {\n const bootStartedAt = performance.now();\n\n // @ts-expect-error virtual module provided by the integration\n bootModule = (await import('virtual:@astroscope/node/boot')) as BootModule;\n\n await withLifecycleSpan('boot', startup.context, () => runStartup(bootModule, context));\n\n bootMs = roundMs(performance.now() - bootStartedAt);\n } catch (err) {\n await failStartup(err, 'startup failed');\n }\n\n const warmupError = await warmup;\n\n if (warmupError !== undefined) {\n await failStartup(warmupError, 'warmup import failed');\n }\n\n if (health) probes.startup.enable();\n\n const client = resolveClientDir(runtimeOptions, import.meta.url);\n const appHandler = createAppHandler(app, runtimeOptions, client);\n const staticHandler = createStaticHandler(app, client);\n const instrument = createRequestInstrumentation({\n logging: runtimeOptions.logging,\n telemetry: runtimeOptions.telemetry ? { exclude: runtimeOptions.telemetry.exclude } : false,\n });\n\n let tls: { cert: Buffer; key: Buffer } | undefined;\n\n try {\n tls = loadTlsOptions();\n } catch (err) {\n await failStartup(err, 'failed to load TLS options');\n }\n\n const listener: http.RequestListener = (req, res) => {\n try {\n decodeURI(req.url ?? '');\n } catch {\n res.writeHead(400);\n res.end('Bad request.');\n\n return;\n }\n\n instrument(req, res, () => {\n if (dispatchNativeMount(req, res)) return;\n\n staticHandler(req, res, () => void appHandler(req, res));\n });\n };\n\n const server = tls ? https.createServer(tls, listener) : http.createServer(listener);\n\n try {\n await withLifecycleSpan('listen', startup.context, () => {\n return new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(port, host, resolve);\n });\n });\n } catch (err) {\n await failStartup(err, `failed to listen on ${host}:${port}`);\n }\n\n if (health) probes.ready.enable();\n\n startup.span.setStatus({ code: SpanStatusCode.OK });\n startup.span.end();\n\n log.info(\n {\n host,\n port,\n ...(tls && { https: true }),\n health: !!health,\n bootMs,\n warmupMs,\n totalMs: roundMs(performance.now() - startedAt),\n },\n 'server ready',\n );\n\n let stopPromise: Promise<void> | undefined;\n let resolveClosed!: () => void;\n\n const closedPromise = new Promise<void>((resolve) => {\n resolveClosed = resolve;\n });\n\n const doStop = async (): Promise<void> => {\n if (health) probes.ready.disable();\n\n log.info('shutdown initiated');\n\n const drainStartedAt = performance.now();\n const shutdown = startLifecycleSpan('shutdown');\n\n await withLifecycleSpan('drain', shutdown.context, async () => {\n const closed = new Promise<void>((resolve) => server.close(() => resolve()));\n\n server.closeIdleConnections();\n\n const forceTimer = setTimeout(() => server.closeAllConnections(), runtimeOptions.shutdownTimeout);\n\n await closed;\n\n clearTimeout(forceTimer);\n });\n\n const drainMs = roundMs(performance.now() - drainStartedAt);\n\n await shutdownLifecycle(shutdown.context);\n\n shutdown.span.end();\n\n log.info({ drainMs }, 'shutdown complete');\n\n await shutdownTelemetry();\n resolveClosed();\n };\n\n const stop = (): Promise<void> => (stopPromise ??= doStop());\n\n process.once('SIGTERM', () => void stop().then(() => process.exit(0)));\n process.once('SIGINT', () => void stop().then(() => process.exit(0)));\n\n return { host, port, stop, closed: () => closedPromise };\n}\n\nif (process.env['ASTROSCOPE_NODE_AUTOSTART'] !== 'disabled') {\n await startServer();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAEA,MAAM,WAAW;;;;;AAOjB,SAAgB,mBAAmB,MAAc,QAAoD;CACnG,MAAM,gBAAgB,UAAU,QAAQ,OAAO;CAC/C,MAAM,OAAO,MAAM,UAAU,QAAQ,CAAC,CAAC,UAAU,MAAM,KAAA,GAAW,aAAa;CAE/E,OAAO;EAAE;EAAM,SAAS,MAAM,QAAQ,eAAe,IAAI;CAAE;AAC7D;AAEA,eAAsB,kBAAqB,MAAc,QAAiB,IAAsC;CAC9G,MAAM,EAAE,MAAM,SAAS,gBAAgB,mBAAmB,MAAM,MAAM;CAEtE,IAAI;EACF,MAAM,SAAS,MAAM,QAAQ,KAAK,aAAa,EAAE;EAEjD,KAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;EAE1C,OAAO;CACT,SAAS,KAAK;EACZ,KAAK,UAAU;GAAE,MAAM,eAAe;GAAO,SAAS,eAAe,QAAQ,IAAI,UAAU;EAAgB,CAAC;EAE5G,MAAM;CACR,UAAU;EACR,KAAK,IAAI;CACX;AACF;;;;;;;;;;;ACrBA,SAAgB,iBAAiB,SAA6C,eAA+B;CAC3G,MAAM,aAAa,IAAI,cAAc,IAAI,IAAI,QAAQ,MAAM,CAAC;CAC5D,MAAM,aAAa,IAAI,cAAc,IAAI,IAAI,QAAQ,MAAM,CAAC;CAC5D,MAAM,MAAM,KAAK,SAAS,YAAY,UAAU;CAChD,MAAM,eAAe,KAAK,SAAS,UAAU;CAE7C,IAAI,uBAAuB,KAAK,QAAQ,aAAa;CACrD,IAAI,WAAW;CAEf,OAAO,CAAC,qBAAqB,SAAS,YAAY,GAAG;EACnD,IAAI,yBAAyB,UAC3B,MAAM,IAAI,MACR,2DAA2D,aAAa,wBAAwB,cAAc,EAChH;EAGF,WAAW;EACX,uBAAuB,KAAK,QAAQ,oBAAoB;CAC1D;CAEA,MAAM,YAAY,IAAI,IAAI,IAAI,SAAS,GAAG,IAAI,MAAM,GAAG,IAAI,IAAI,GAAG,qBAAqB,WAAW;CAElG,OAAO,IAAI,cAAc,SAAS;AACpC;;;ACvBA,eAAe,gBAAgB,QAAgB,QAA+C;CAC5F,MAAM,YAAY,CAAC,GAAG,OAAO,QAAQ,GAAG,OAAO,YAAY;CAE3D,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,WAAW,KAAK,KAAK,QAAQ,QAAQ;EAC3C,IAAI;EAEJ,IAAI;GACF,SAAS,iBAAiB,QAAQ;GAElC,MAAM,IAAI,SAAe,SAAS,WAAW;IAC3C,OAAQ,KAAK,cAAc,QAAQ,CAAC;IACpC,OAAQ,KAAK,SAAS,MAAM;GAC9B,CAAC;GAED,OAAO,IAAI,SAAS,SAAS,MAAM,MAAM,GAAqB,EAC5D,SAAS,EAAE,gBAAgB,2BAA2B,EACxD,CAAC;EACH,QAAQ;GACN,QAAQ,QAAQ;EAClB;CACF;AAGF;;;;;;AAOA,SAAgB,iBAAiB,KAAc,SAAyB,QAAgB;CACtF,QAAQ,GAAG,uBAAuB,WAAW;EAC3C,MAAM,aAAa,iBAAiB,CAAC,EAAE;EAEvC,IAAI,MACF;GACE,GAAI,kBAAkB,QAAQ,EAAE,KAAK,OAAO,IAAI,EAAE,OAAO;GACzD,GAAI,cAAc,EAAE,KAAK,WAAW;EACtC,GACA,aAAa,wCAAwC,qBACvD;CACF,CAAC;CAED,MAAM,4BAA4B,OAAO,QAAmC;EAC1E,MAAM,EAAE,aAAa,IAAI,IAAI,GAAG;EAEhC,KAAK,MAAM,UAAU,CAAC,KAAK,GAAG,GAC5B,IAAI,SAAS,SAAS,IAAI,OAAO,MAAM,KAAK,SAAS,SAAS,IAAI,OAAO,YAAY,GAAG;GACtF,MAAM,WAAW,MAAM,gBAAgB,QAAQ,MAAM;GAErD,IAAI,UAAU,OAAO;EACvB;EAGF,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CAC3C;CAEA,MAAM,gBACJ,QAAQ,kBAAkB,KAAK,QAAQ,kBAAkB,OAAO,oBAC5D,KAAA,IACA,QAAQ;CAEd,OAAO,OAAO,KAAsB,QAAuC;EACzE,IAAI;EAEJ,IAAI;GACF,UAAU,6BAA6B,KAAK;IAC1C,gBAAgB,IAAI,oBAAoB,KAAK,CAAC;IAC9C,GAAI,kBAAkB,KAAA,KAAa,EAAE,cAAc;IACnD,MAAM,QAAQ;GAChB,CAAC;EACH,SAAS,KAAK;GACZ,IAAI,MAAM,eAAe,QAAQ;IAAE;IAAK,KAAK,IAAI;GAAI,IAAI;IAAE,QAAQ;IAAK,KAAK,IAAI;GAAI,GAAG,kBAAkB;GAE1G,IAAI,aAAa;GACjB,IAAI,IAAI,uBAAuB;GAE/B;EACF;EAEA,MAAM,YAAY,IAAI,MAAM,SAAS,IAAI;EACzC,MAAM,UAAU,aAAa,EAAE,UAAU,SAAS,UAAU,UAAU,aAAa,YAAY,KAAA;EAE/F,IAAI,SACF,oBAAoB,SAAS,OAAO;EAGtC,MAAM,WAAW,UACb,MAAM,IAAI,OAAO,SAAS;GAAE,iBAAiB;GAAM,WAAW;GAAS;EAA0B,CAAC,IAClG,MAAM,IAAI,OAAO,SAAS;GAAE,iBAAiB;GAAM;EAA0B,CAAC;EAElF,MAAM,cAAc,UAAU,GAAG;CACnC;AACF;;;AClGA,MAAM,WAAW,CACf;CAAE,UAAU;CAAM,QAAQ;AAAM,GAChC;CAAE,UAAU;CAAQ,QAAQ;AAAM,CACpC;AAEA,SAAS,iBACP,KACA,QACA,UACoD;CACpD,MAAM,SAAS,IAAI,QAAQ;CAE3B,IAAI,OAAO,WAAW,UAAU,OAAO,KAAA;CAEvC,KAAK,MAAM,EAAE,UAAU,YAAY,UAAU;EAC3C,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;EAEhC,IAAI,GAAG,WAAW,KAAK,KAAK,QAAQ,GAAG,WAAW,QAAQ,CAAC,GACzD,OAAO;GAAE,UAAU,GAAG,WAAW;GAAU;EAAS;CAExD;AAGF;AAEA,SAAS,iBAAiB,UAA2B;CACnD,MAAM,OAAO,SAAS,MAAM,GAAG,CAAC,CAAC,IAAI;CAErC,OAAO,CAAC,CAAC,QAAQ,KAAK,SAAS,GAAG;AACpC;AAEA,SAAS,oBAAoB,UAA0B;CACrD,OAAO,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI;AACnD;AAEA,SAAS,YAAY,QAAgB,SAA0B;CAC7D,MAAM,WAAW,KAAK,KAAK,QAAQ,OAAO;CAC1C,MAAM,WAAW,KAAK,QAAQ,QAAQ;CACtC,MAAM,iBAAiB,KAAK,QAAQ,MAAM;CAG1C,IAAI,aAAa,kBAAkB,CAAC,SAAS,WAAW,iBAAiB,KAAK,GAAG,GAC/E,OAAO;CAGT,IAAI;EACF,OAAO,GAAG,UAAU,QAAQ,CAAC,CAAC,YAAY;CAC5C,QAAQ;EACN,OAAO;CACT;AACF;;;;;;AAOA,SAAgB,oBAAoB,KAAc,QAAgB;CAChE,QAAQ,KAAsB,KAAqB,QAA0B;EAC3E,IAAI,CAAC,IAAI,KAAK;GACZ,IAAI;GAEJ;EACF;EAEA,IAAI,UAAU,IAAI;EAElB,IAAI,QAAQ,SAAS,GAAG,GACtB,UAAU,QAAQ,MAAM,GAAG,QAAQ,QAAQ,GAAG,CAAC;EAGjD,MAAM,CAAC,UAAU,IAAI,YAAY,QAAQ,MAAM,GAAG;EAClD,IAAI,SAAS,IAAI,WAAW,OAAO;EAEnC,IAAI;GACF,SAAS,UAAU,MAAM;EAC3B,QAAQ,CAER;EAEA,MAAM,MAAM,YAAY,QAAQ,MAAM;EACtC,MAAM,WAAW,QAAQ,SAAS,GAAG;EACrC,IAAI,WAAW;EAEf,QAAQ,IAAI,SAAS,eAArB;GACE,KAAK;IACH,IAAI,OAAO,YAAY,OAAO,UAAU;KACtC,IAAI,aAAa;KACjB,IAAI,UAAU,YAAY,QAAQ,MAAM,GAAG,EAAE,KAAK,WAAW,IAAI,aAAa,GAAG;KACjF,IAAI,IAAI;KAER;IACF;IAEA,IAAI,OAAO,CAAC,UACV,WAAW,GAAG,QAAQ;IAGxB;GAEF,KAAK;IACH,IAAI,OAAO,CAAC,UACV,WAAW,GAAG,QAAQ;IAGxB;GAEF,KAAK,UACH,IAAI,CAAC,YAAY,CAAC,iBAAiB,OAAO,KAAK,CAAC,QAAQ,WAAW,IAAI,GAAG;IACxE,IAAI,aAAa;IACjB,IAAI,UAAU,YAAY,GAAG,QAAQ,GAAG,WAAW,IAAI,aAAa,IAAI;IACxE,IAAI,IAAI;IAER;GACF;EAIJ;EAEA,WAAW,oBAAoB,IAAI,WAAW,QAAQ,CAAC;EAEvD,MAAM,qBAAqB,KAAK,MAAM,UAAU,QAAQ;EACxD,MAAM,eAAe,aAAa,IAAI,KAAK,MAAM,QAAQ,kBAAkB,CAAC;EAC5E,MAAM,UAAU,eAAe,iBAAiB,KAAK,QAAQ,kBAAkB,IAAI,KAAA;EAEnF,MAAM,SAAS,KAAK,KAAK,SAAS,YAAY,oBAAoB;GAChE,MAAM;GACN,UAAU,mBAAmB,WAAW,eAAe,IAAI,UAAU;GAGrE,YAAY,IAAI,SAAS,gBAAgB,UAAU,IAAI,SAAS,gBAAgB,aAAa,CAAC,MAAM,IAAI,CAAC;EAC3G,CAAC;EAED,IAAI,eAAe;EAEnB,OAAO,GAAG,UAAU,QAAyD;GAC3E,IAAI,cAAc;IAChB,MAAM,SAAS,IAAI,cAAc;IAEjC,IAAI,UAAU,KACZ,QAAQ,MAAM,IAAI,SAAS,CAAC;IAG9B,IAAI,UAAU,MAAM;IACpB,IAAI,IAAI,UAAU,MAAM,0BAA0B,EAAE;IAEpD;GACF;GAEA,IAAI;EACN,CAAC;EAED,OAAO,GAAG,cAAc;GACtB,eAAe;EACjB,CAAC;EAID,OAAO,GAAG,YAAY,eAA+B;GACnD,IAAI,cACF,WAAW,UAAU,QAAQ,iBAAiB;GAGhD,IAAI,SAAS;IACX,WAAW,UAAU,oBAAoB,QAAQ,QAAQ;IACzD,WAAW,UACT,gBACA,WAAW,IAAI,KAAK,MAAM,QAAQ,kBAAkB,CAAC,KAAK,0BAC5D;GACF;GAEA,IAAI,mBAAmB,WAAW,IAAI,IAAI,SAAS,UAAU,EAAE,GAC7D,WAAW,UAAU,iBAAiB,qCAAqC;EAE/E,CAAC;EAED,OAAO,KAAK,GAAG;CACjB;AACF;;;ACjKA,WAAW,QAAQ,QAAQ,IAAI,IAAI;AAEnC,MAAM,iBAAiB;AACvB,MAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAEzC,MAAM,WAAW,MAAc,KAAK,MAAM,IAAI,GAAG,IAAI;;;;;;AAOrD,eAAe,gBAA+B;CAC5C,MAAM,UAAU;EACd,GAAI,IAAI,SAAS,SAAS,OAAO,KAAK,CAAC;EACvC,IAAI,SAAS;EACb,IAAI,SAAS;EACb,IAAI,SAAS;EACb,IAAI,SAAS;CACf,CAAC,CAAC,QAAQ,SAAS,SAAS,KAAA,CAAS;CAGrC,MAAM,YAAW,MADK,QAAQ,WAAW,QAAQ,KAAK,SAAS,KAAK,CAAC,CAAC,EAAA,CAC7C,QAAQ,WAAW,OAAO,WAAW,UAAU;CAExE,IAAI,SAAS,WAAW,GAAG;CAE3B,KAAK,MAAM,WAAW,UACpB,IAAI,MACF,QAAQ,kBAAkB,QAAQ,EAAE,KAAK,QAAQ,OAAO,IAAI,EAAE,QAAQ,QAAQ,OAAO,GACrF,sBACF;CAMF,MAAM,IAAI,eACR,SAAS,KAAK,YAAY,QAAQ,MAAM,GACxC,sBACF;AACF;;;;;AAMA,SAAS,iBAA4D;CACnE,MAAM,WAAW,QAAQ,IAAI;CAC7B,MAAM,UAAU,QAAQ,IAAI;CAE5B,IAAI,CAAC,YAAY,CAAC,SAAS,OAAO,KAAA;CAElC,IAAI,CAAC,YAAY,CAAC,SAChB,MAAM,IAAI,MAAM,sEAAsE;CAGxF,OAAO;EAAE,MAAM,GAAG,aAAa,QAAQ;EAAG,KAAK,GAAG,aAAa,OAAO;CAAE;AAC1E;AASA,eAAsB,YAAY,WAGR;CACxB,MAAM,YAAY,YAAY,IAAI;CAClC,MAAM,OAAO,WAAW,QAAQ,QAAQ,IAAI,WAAW,eAAe;CACtE,MAAM,OAAO,WAAW,SAAS,QAAQ,IAAI,UAAU,OAAO,QAAQ,IAAI,OAAO,IAAI,eAAe;CACpG,MAAM,UAAuB;EAAE,KAAK;EAAO;EAAM;CAAK;CACtD,MAAM,SAAS,eAAe;CAE9B,eAAe,OAAO;CAEtB,IAAI;EACF,MAAM,gBAAgB;GACpB,KAAK;GACL,WAAW,eAAe,YAAY,EAAE,YAAY,eAAe,UAAU,WAAW,IAAI;GAC5F,OAAO;IACL,cAAc,OAAO;IACrB,uBAAuB,OAAO;IAC9B,WAAW,OAAO;GACpB;EACF,CAAC;CACH,SAAS,KAAK;EAEZ,cAAc;EACd,QAAQ,MAAM,GAAG;EACjB,QAAQ,KAAK,CAAC;CAChB;CAEA,IAAI,QAAQ;EACV,OAAa,MAAM;GAAE,GAAG;GAAQ,MAAM,OAAO,QAAQ,QAAQ,IAAI,kBAAkB;EAAU,CAAC;EAC9F,OAAO,KAAK,OAAO;EACnB,qBAAqB,MAAM;EAC3B,IAAI,MAAM,yBAAyB;CACrC;CAEA,MAAM,UAAU,mBAAmB,SAAS;CAE5C,IAAI,KAAK;EAAE;EAAM;CAAK,GAAG,UAAU;CAInC,IAAI,aAAyB,CAAC;CAC9B,IAAI,SAAS;CACb,IAAI,WAAW;CAKf,MAAM,kBAAkB,YAAY,IAAI;CACxC,MAAM,aAAa,mBAAmB,UAAU,QAAQ,OAAO;CAC/D,MAAM,SAAS,cAAc,CAAC,CAAC,WACvB;EACJ,WAAW,QAAQ,YAAY,IAAI,IAAI,eAAe;EACtD,WAAW,KAAK,IAAI;CAGtB,IACC,UAAmB;EAClB,WAAW,QAAQ,YAAY,IAAI,IAAI,eAAe;EACtD,WAAW,KAAK,UAAU;GAAE,MAAM,eAAe;GAAO,SAAS;EAAuB,CAAC;EACzF,WAAW,KAAK,IAAI;EAEpB,OAAO;CACT,CACF;CAEA,MAAM,oBAAoB,OACxB,oBACkB;EAClB,IAAI;GACF,IAAI,iBACF,MAAM,kBAAkB,cAAc,uBAAuB,YAAY,YAAY,OAAO,CAAC;QAE7F,MAAM,YAAY,YAAY,OAAO;EAEzC,SAAS,KAAK;GACZ,IAAI,MAAM,eAAe,QAAQ,EAAE,IAAI,IAAI,EAAE,QAAQ,IAAI,GAAG,iBAAiB;EAC/E;EAEA,kBAAkB;EAElB,IAAI,QAAQ;GACV,uBAAuB;GAEvB,IAAI;IACF,MAAMA,OAAa,KAAK;GAC1B,SAAS,KAAK;IAGZ,IAAI,MAAM,eAAe,QAAQ,EAAE,IAAI,IAAI,EAAE,QAAQ,IAAI,GAAG,iCAAiC;GAC/F;EACF;CACF;CAEA,MAAM,cAAc,OAAO,KAAc,YAAoC;EAC3E,IAAI,MAAM,eAAe,QAAQ,EAAE,IAAI,IAAI,EAAE,QAAQ,IAAI,GAAG,OAAO;EACnE,QAAQ,KAAK,UAAU;GAAE,MAAM,eAAe;GAAO;EAAQ,CAAC;EAC9D,QAAQ,KAAK,IAAI;EAEjB,MAAM,kBAAkB;EACxB,MAAM,kBAAkB;EACxB,QAAQ,KAAK,CAAC;CAChB;CAEA,IAAI;EACF,MAAM,gBAAgB,YAAY,IAAI;EAGtC,aAAc,MAAM,OAAO;EAE3B,MAAM,kBAAkB,QAAQ,QAAQ,eAAe,WAAW,YAAY,OAAO,CAAC;EAEtF,SAAS,QAAQ,YAAY,IAAI,IAAI,aAAa;CACpD,SAAS,KAAK;EACZ,MAAM,YAAY,KAAK,gBAAgB;CACzC;CAEA,MAAM,cAAc,MAAM;CAE1B,IAAI,gBAAgB,KAAA,GAClB,MAAM,YAAY,aAAa,sBAAsB;CAGvD,IAAI,QAAQ,OAAO,QAAQ,OAAO;CAElC,MAAM,SAAS,iBAAiB,gBAAgB,YAAY,GAAG;CAC/D,MAAM,aAAa,iBAAiB,KAAK,gBAAgB,MAAM;CAC/D,MAAM,gBAAgB,oBAAoB,KAAK,MAAM;CACrD,MAAM,aAAa,6BAA6B;EAC9C,SAAS,eAAe;EACxB,WAAW,eAAe,YAAY,EAAE,SAAS,eAAe,UAAU,QAAQ,IAAI;CACxF,CAAC;CAED,IAAI;CAEJ,IAAI;EACF,MAAM,eAAe;CACvB,SAAS,KAAK;EACZ,MAAM,YAAY,KAAK,4BAA4B;CACrD;CAEA,MAAM,YAAkC,KAAK,QAAQ;EACnD,IAAI;GACF,UAAU,IAAI,OAAO,EAAE;EACzB,QAAQ;GACN,IAAI,UAAU,GAAG;GACjB,IAAI,IAAI,cAAc;GAEtB;EACF;EAEA,WAAW,KAAK,WAAW;GACzB,IAAI,oBAAoB,KAAK,GAAG,GAAG;GAEnC,cAAc,KAAK,WAAW,KAAK,WAAW,KAAK,GAAG,CAAC;EACzD,CAAC;CACH;CAEA,MAAMC,WAAS,MAAM,MAAM,aAAa,KAAK,QAAQ,IAAI,KAAK,aAAa,QAAQ;CAEnF,IAAI;EACF,MAAM,kBAAkB,UAAU,QAAQ,eAAe;GACvD,OAAO,IAAI,SAAe,SAAS,WAAW;IAC5C,SAAO,KAAK,SAAS,MAAM;IAC3B,SAAO,OAAO,MAAM,MAAM,OAAO;GACnC,CAAC;EACH,CAAC;CACH,SAAS,KAAK;EACZ,MAAM,YAAY,KAAK,uBAAuB,KAAK,GAAG,MAAM;CAC9D;CAEA,IAAI,QAAQ,OAAO,MAAM,OAAO;CAEhC,QAAQ,KAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;CAClD,QAAQ,KAAK,IAAI;CAEjB,IAAI,KACF;EACE;EACA;EACA,GAAI,OAAO,EAAE,OAAO,KAAK;EACzB,QAAQ,CAAC,CAAC;EACV;EACA;EACA,SAAS,QAAQ,YAAY,IAAI,IAAI,SAAS;CAChD,GACA,cACF;CAEA,IAAI;CACJ,IAAI;CAEJ,MAAM,gBAAgB,IAAI,SAAe,YAAY;EACnD,gBAAgB;CAClB,CAAC;CAED,MAAM,SAAS,YAA2B;EACxC,IAAI,QAAQ,OAAO,MAAM,QAAQ;EAEjC,IAAI,KAAK,oBAAoB;EAE7B,MAAM,iBAAiB,YAAY,IAAI;EACvC,MAAM,WAAW,mBAAmB,UAAU;EAE9C,MAAM,kBAAkB,SAAS,SAAS,SAAS,YAAY;GAC7D,MAAM,SAAS,IAAI,SAAe,YAAYA,SAAO,YAAY,QAAQ,CAAC,CAAC;GAE3E,SAAO,qBAAqB;GAE5B,MAAM,aAAa,iBAAiBA,SAAO,oBAAoB,GAAG,eAAe,eAAe;GAEhG,MAAM;GAEN,aAAa,UAAU;EACzB,CAAC;EAED,MAAM,UAAU,QAAQ,YAAY,IAAI,IAAI,cAAc;EAE1D,MAAM,kBAAkB,SAAS,OAAO;EAExC,SAAS,KAAK,IAAI;EAElB,IAAI,KAAK,EAAE,QAAQ,GAAG,mBAAmB;EAEzC,MAAM,kBAAkB;EACxB,cAAc;CAChB;CAEA,MAAM,aAA6B,gBAAgB,OAAO;CAE1D,QAAQ,KAAK,iBAAiB,KAAK,KAAK,CAAC,CAAC,WAAW,QAAQ,KAAK,CAAC,CAAC,CAAC;CACrE,QAAQ,KAAK,gBAAgB,KAAK,KAAK,CAAC,CAAC,WAAW,QAAQ,KAAK,CAAC,CAAC,CAAC;CAEpE,OAAO;EAAE;EAAM;EAAM;EAAM,cAAc;CAAc;AACzD;AAEA,IAAI,QAAQ,IAAI,iCAAiC,YAC/C,MAAM,YAAY"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { n as log } from "./log-B69HEBvg.js";
|
|
2
|
+
import { n as getIslandEmitters } from "./emitters-C20tjKLp.js";
|
|
3
|
+
import { RewritingStream } from "parse5-html-rewriting-stream";
|
|
4
|
+
//#region src/islands/graph.ts
|
|
5
|
+
function createClosure(chunks, edges) {
|
|
6
|
+
const cache = /* @__PURE__ */ new Map();
|
|
7
|
+
const walk = (fileName, result, visited) => {
|
|
8
|
+
if (visited.has(fileName)) return;
|
|
9
|
+
visited.add(fileName);
|
|
10
|
+
const entry = chunks[fileName];
|
|
11
|
+
if (!entry) return;
|
|
12
|
+
for (const dep of edges(entry)) {
|
|
13
|
+
result.add(dep);
|
|
14
|
+
walk(dep, result, visited);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
return (fileName) => {
|
|
18
|
+
const cached = cache.get(fileName);
|
|
19
|
+
if (cached) return cached;
|
|
20
|
+
const result = /* @__PURE__ */ new Set();
|
|
21
|
+
walk(fileName, result, /* @__PURE__ */ new Set());
|
|
22
|
+
result.delete(fileName);
|
|
23
|
+
const list = [...result];
|
|
24
|
+
cache.set(fileName, list);
|
|
25
|
+
return list;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function createChunkGraph(manifest) {
|
|
29
|
+
return {
|
|
30
|
+
staticClosure: createClosure(manifest.chunks, (entry) => entry.i ?? []),
|
|
31
|
+
fullClosure: createClosure(manifest.chunks, (entry) => [...entry.i ?? [], ...entry.d ?? []]),
|
|
32
|
+
has: (fileName) => fileName in manifest.chunks
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/islands/rewriter.ts
|
|
37
|
+
const ISLAND = "astro-island";
|
|
38
|
+
function encodeAttribute(value) {
|
|
39
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
40
|
+
}
|
|
41
|
+
function createIslandRewriter(onIsland) {
|
|
42
|
+
const stream = new RewritingStream();
|
|
43
|
+
const out = [];
|
|
44
|
+
stream.on("data", (chunk) => {
|
|
45
|
+
out.push(typeof chunk === "string" ? chunk : chunk.toString());
|
|
46
|
+
});
|
|
47
|
+
stream.on("startTag", (tag, rawHtml) => {
|
|
48
|
+
if (tag.tagName === ISLAND) {
|
|
49
|
+
const attrs = {};
|
|
50
|
+
for (const attr of tag.attrs) attrs[attr.name] = attr.value;
|
|
51
|
+
const rewrite = onIsland(attrs);
|
|
52
|
+
if (rewrite?.prepend) stream.emitRaw(rewrite.prepend);
|
|
53
|
+
}
|
|
54
|
+
stream.emitRaw(rawHtml);
|
|
55
|
+
});
|
|
56
|
+
const drain = () => out.splice(0).join("");
|
|
57
|
+
return {
|
|
58
|
+
write(chunk) {
|
|
59
|
+
stream.write(chunk);
|
|
60
|
+
return drain();
|
|
61
|
+
},
|
|
62
|
+
end() {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
stream.once("error", reject);
|
|
65
|
+
stream.end(() => resolve(drain()));
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const IMMEDIATE_DIRECTIVES = /* @__PURE__ */ new Set(["load", "only"]);
|
|
71
|
+
/** urls cannot contain `<\/script>`, but escape `<` anyway so no value ever can */
|
|
72
|
+
function jsonForScript(value) {
|
|
73
|
+
return JSON.stringify(value).replace(/</g, "\\u003c");
|
|
74
|
+
}
|
|
75
|
+
function createIslandsTransformer(manifest) {
|
|
76
|
+
const graph = createChunkGraph(manifest);
|
|
77
|
+
const fileNames = Object.keys(manifest.chunks);
|
|
78
|
+
const resolveCache = /* @__PURE__ */ new Map();
|
|
79
|
+
const resolve = (url) => {
|
|
80
|
+
const cached = resolveCache.get(url);
|
|
81
|
+
if (cached !== void 0) return cached;
|
|
82
|
+
let resolved = null;
|
|
83
|
+
for (const fileName of fileNames) if (url.endsWith(fileName)) {
|
|
84
|
+
const boundary = url.length - fileName.length;
|
|
85
|
+
if (boundary === 0 || url[boundary - 1] === "/") {
|
|
86
|
+
resolved = {
|
|
87
|
+
prefix: url.slice(0, boundary),
|
|
88
|
+
fileName
|
|
89
|
+
};
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
resolveCache.set(url, resolved);
|
|
94
|
+
return resolved;
|
|
95
|
+
};
|
|
96
|
+
const createDocumentRewriter = (context) => {
|
|
97
|
+
const emittedLinks = /* @__PURE__ */ new Set();
|
|
98
|
+
const registeredComponents = /* @__PURE__ */ new Set();
|
|
99
|
+
let runtimeInjected = false;
|
|
100
|
+
return createIslandRewriter((attrs) => {
|
|
101
|
+
const componentUrl = attrs["component-url"];
|
|
102
|
+
if (!componentUrl) return null;
|
|
103
|
+
const component = resolve(componentUrl);
|
|
104
|
+
if (!component) return null;
|
|
105
|
+
const rendererUrl = attrs["renderer-url"] || null;
|
|
106
|
+
const renderer = rendererUrl ? resolve(rendererUrl) : null;
|
|
107
|
+
const closureUrls = (closure) => {
|
|
108
|
+
const urls = /* @__PURE__ */ new Set([componentUrl, ...closure(component.fileName).map((f) => component.prefix + f)]);
|
|
109
|
+
if (rendererUrl) {
|
|
110
|
+
urls.add(rendererUrl);
|
|
111
|
+
for (const f of renderer ? closure(renderer.fileName) : []) urls.add(renderer.prefix + f);
|
|
112
|
+
}
|
|
113
|
+
return [...urls];
|
|
114
|
+
};
|
|
115
|
+
const island = {
|
|
116
|
+
componentUrl,
|
|
117
|
+
rendererUrl,
|
|
118
|
+
client: attrs["client"] || null,
|
|
119
|
+
staticClosure: closureUrls(graph.staticClosure),
|
|
120
|
+
fullClosure: closureUrls(graph.fullClosure)
|
|
121
|
+
};
|
|
122
|
+
const emissions = [{ links: island.staticClosure }];
|
|
123
|
+
for (const emitter of getIslandEmitters()) try {
|
|
124
|
+
const emission = emitter(island, context);
|
|
125
|
+
if (emission) emissions.push(emission);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
log.error({
|
|
128
|
+
err: error,
|
|
129
|
+
componentUrl
|
|
130
|
+
}, "island emitter failed");
|
|
131
|
+
}
|
|
132
|
+
const links = [...new Set(emissions.flatMap((e) => e.links ?? []))];
|
|
133
|
+
const html = emissions.map((e) => e.html ?? "").join("");
|
|
134
|
+
const directive = (island.client ?? "").replace(/-x$/, "");
|
|
135
|
+
if (IMMEDIATE_DIRECTIVES.has(directive)) {
|
|
136
|
+
const fresh = links.filter((url) => !emittedLinks.has(url));
|
|
137
|
+
for (const url of fresh) emittedLinks.add(url);
|
|
138
|
+
return { prepend: html + fresh.map((url) => `<link rel="modulepreload" fetchpriority="low" href="${encodeAttribute(url)}">`).join("") || void 0 };
|
|
139
|
+
}
|
|
140
|
+
if (registeredComponents.has(componentUrl)) return { prepend: html || void 0 };
|
|
141
|
+
registeredComponents.add(componentUrl);
|
|
142
|
+
const runtime = runtimeInjected ? "" : `<script type="module" src="${encodeAttribute(component.prefix + manifest.runtime)}"><\/script>`;
|
|
143
|
+
runtimeInjected = true;
|
|
144
|
+
return { prepend: runtime + `<script>(self.__islands__??={})[${jsonForScript(componentUrl)}]=${jsonForScript(links)};<\/script>` + html || void 0 };
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
return { createDocumentRewriter };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The single streaming pass over an html page response: chunks go through the
|
|
151
|
+
* islands rewriter (when present), head content is inserted right after the
|
|
152
|
+
* opening `<head>` tag (which requires buffering the whole document — head
|
|
153
|
+
* content is dev-style delivery, where throughput is irrelevant), and end
|
|
154
|
+
* factories run last, strictly after every island passed the rewriter.
|
|
155
|
+
*/
|
|
156
|
+
function createPageTransformStream(options) {
|
|
157
|
+
const { rewriter, heads, ends } = options;
|
|
158
|
+
const decoder = new TextDecoder();
|
|
159
|
+
const encoder = new TextEncoder();
|
|
160
|
+
const buffered = heads.length > 0 ? [] : null;
|
|
161
|
+
const enqueue = (controller, text) => {
|
|
162
|
+
if (text) controller.enqueue(encoder.encode(text));
|
|
163
|
+
};
|
|
164
|
+
return new TransformStream({
|
|
165
|
+
transform(chunk, controller) {
|
|
166
|
+
let text = decoder.decode(chunk, { stream: true });
|
|
167
|
+
if (rewriter) text = rewriter.write(text);
|
|
168
|
+
if (buffered) buffered.push(text);
|
|
169
|
+
else enqueue(controller, text);
|
|
170
|
+
},
|
|
171
|
+
async flush(controller) {
|
|
172
|
+
let tail = decoder.decode();
|
|
173
|
+
if (rewriter) tail = (tail ? rewriter.write(tail) : "") + await rewriter.end();
|
|
174
|
+
if (buffered) {
|
|
175
|
+
const html = buffered.join("") + tail;
|
|
176
|
+
const head = /<head[^>]*>/i.exec(html);
|
|
177
|
+
const at = head ? head.index + head[0].length : 0;
|
|
178
|
+
enqueue(controller, html.slice(0, at) + heads.join("") + html.slice(at));
|
|
179
|
+
} else enqueue(controller, tail);
|
|
180
|
+
for (const end of ends) try {
|
|
181
|
+
enqueue(controller, end() ?? "");
|
|
182
|
+
} catch (error) {
|
|
183
|
+
log.error({ err: error }, "document emitter failed");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { createPageTransformStream as n, createIslandsTransformer as t };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=transform-D8dIBGEr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-D8dIBGEr.js","names":[],"sources":["../src/islands/graph.ts","../src/islands/rewriter.ts","../src/islands/transform.ts"],"sourcesContent":["import type { IslandsManifest } from './types.js';\n\n/**\n * Closure computation over the chunk import graph, memoized per manifest. The\n * manifest stores direct edges only — flattened closures repeat heavily across\n * entries and would bloat the JSON.\n */\nexport type ChunkGraph = {\n /** transitive static imports of a chunk, the chunk itself excluded */\n staticClosure(fileName: string): string[];\n /** transitive static + dynamic imports of a chunk, the chunk itself excluded */\n fullClosure(fileName: string): string[];\n has(fileName: string): boolean;\n};\n\nfunction createClosure(\n chunks: IslandsManifest['chunks'],\n edges: (entry: { i?: string[] | undefined; d?: string[] | undefined }) => string[],\n): (fileName: string) => string[] {\n const cache = new Map<string, string[]>();\n\n const walk = (fileName: string, result: Set<string>, visited: Set<string>): void => {\n if (visited.has(fileName)) {\n return;\n }\n\n visited.add(fileName);\n\n const entry = chunks[fileName];\n\n if (!entry) {\n return;\n }\n\n for (const dep of edges(entry)) {\n result.add(dep);\n walk(dep, result, visited);\n }\n };\n\n return (fileName) => {\n const cached = cache.get(fileName);\n\n if (cached) {\n return cached;\n }\n\n const result = new Set<string>();\n\n walk(fileName, result, new Set());\n result.delete(fileName);\n\n const list = [...result];\n\n cache.set(fileName, list);\n\n return list;\n };\n}\n\nexport function createChunkGraph(manifest: IslandsManifest): ChunkGraph {\n return {\n staticClosure: createClosure(manifest.chunks, (entry) => entry.i ?? []),\n fullClosure: createClosure(manifest.chunks, (entry) => [...(entry.i ?? []), ...(entry.d ?? [])]),\n has: (fileName) => fileName in manifest.chunks,\n };\n}\n","import { RewritingStream } from 'parse5-html-rewriting-stream';\n\n/**\n * Streaming HTML rewriter that finds `<astro-island …>` opening tags, hands their\n * attributes to a handler, and prepends the handler's html before the tag — the\n * tag itself is always re-emitted from its raw source, byte-verbatim.\n *\n * Tokenization is parse5's — the reference WHATWG implementation — so every\n * context where island markup is not actually an element to the browser\n * (comments, raw-text elements like `script`/`iframe`/`noscript`, doctypes,\n * quoted attribute values) is skipped by construction rather than by our own\n * spec-tracking; unmodified content passes through as raw source slices.\n * Attribute values arrive with the full entity set decoded.\n *\n * Closing tags are never touched: injection happens before the island's opening\n * tag precisely so the island's subtree — the hydration target — stays untouched.\n *\n * The test suite pins the behavior this package relies on, so a parse5 upgrade\n * that changes it fails here rather than degrading silently — same philosophy as\n * the astro compatibility surface.\n */\n\nexport type IslandTagRewrite = {\n /** html emitted immediately before the island opening tag */\n prepend?: string | undefined;\n};\n\nexport type IslandTagHandler = (attrs: Record<string, string>) => IslandTagRewrite | null;\n\nexport type IslandRewriter = {\n write(chunk: string): string;\n end(): Promise<string>;\n};\n\nconst ISLAND = 'astro-island';\n\nexport function encodeAttribute(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\nexport function createIslandRewriter(onIsland: IslandTagHandler): IslandRewriter {\n const stream = new RewritingStream();\n const out: string[] = [];\n\n stream.on('data', (chunk: string | Buffer) => {\n out.push(typeof chunk === 'string' ? chunk : chunk.toString());\n });\n\n stream.on('startTag', (tag, rawHtml) => {\n if (tag.tagName === ISLAND) {\n const attrs: Record<string, string> = {};\n\n for (const attr of tag.attrs) {\n attrs[attr.name] = attr.value;\n }\n\n const rewrite = onIsland(attrs);\n\n if (rewrite?.prepend) {\n stream.emitRaw(rewrite.prepend);\n }\n }\n\n stream.emitRaw(rawHtml);\n });\n\n const drain = (): string => out.splice(0).join('');\n\n return {\n // a transform stream with an attached data listener processes writes\n // synchronously, so each write can hand back its output right away\n write(chunk) {\n stream.write(chunk);\n\n return drain();\n },\n end() {\n return new Promise((resolve, reject) => {\n stream.once('error', reject);\n stream.end(() => resolve(drain()));\n });\n },\n };\n}\n","import type { APIContext } from 'astro';\nimport { log } from '../observability/log/index.js';\nimport { getIslandEmitters } from './emitters.js';\nimport { createChunkGraph } from './graph.js';\nimport { type IslandRewriter, createIslandRewriter, encodeAttribute } from './rewriter.js';\nimport type { IslandEmission, IslandInfo, IslandsManifest } from './types.js';\n\n/**\n * Turns the manifest into per-document rewriters: resolves each island's chunk\n * closures, collects emissions (the built-in preloader plus registered emitters),\n * and applies the emission policy —\n *\n * - immediate directives (`load`, `only`) get `<link rel=\"modulepreload\">` tags\n * before the tag, deduplicated per document; the browser's speculative preload\n * scanner acts on them from raw bytes, ahead of any script.\n * - deferred directives get an inline script before the first island per\n * component that registers the links on the preload global, keyed by\n * `component-url`; the gate runtime fires them by the directive's own\n * scheduling semantics. A script rather than an attribute: it takes effect at\n * parse time and its effect survives the island element being removed — the\n * island tag itself stays untouched.\n *\n * The gate runtime script is injected once, before the first island that needs it,\n * so pages without deferred islands never load it.\n */\n\n/** global registry of preload urls per component-url, written by the transform, read by the gate runtime */\nexport const PRELOAD_GLOBAL = '__islands__';\n\nconst IMMEDIATE_DIRECTIVES = new Set(['load', 'only']);\n\n/** urls cannot contain `</script>`, but escape `<` anyway so no value ever can */\nfunction jsonForScript(value: unknown): string {\n return JSON.stringify(value).replace(/</g, '\\\\u003c');\n}\n\ntype ResolvedChunk = { prefix: string; fileName: string };\n\nexport type IslandsTransformer = {\n createDocumentRewriter(context?: APIContext | undefined): IslandRewriter;\n};\n\nexport function createIslandsTransformer(manifest: IslandsManifest): IslandsTransformer {\n const graph = createChunkGraph(manifest);\n const fileNames = Object.keys(manifest.chunks);\n const resolveCache = new Map<string, ResolvedChunk | null>();\n\n // islands carry public urls (base and asset prefix baked in), the manifest holds\n // dist-relative file names — match by suffix at a path boundary, so the observed\n // prefix maps closures and the runtime script back to public urls with no config\n const resolve = (url: string): ResolvedChunk | null => {\n const cached = resolveCache.get(url);\n\n if (cached !== undefined) {\n return cached;\n }\n\n let resolved: ResolvedChunk | null = null;\n\n for (const fileName of fileNames) {\n if (url.endsWith(fileName)) {\n const boundary = url.length - fileName.length;\n\n if (boundary === 0 || url[boundary - 1] === '/') {\n resolved = { prefix: url.slice(0, boundary), fileName };\n break;\n }\n }\n }\n\n resolveCache.set(url, resolved);\n\n return resolved;\n };\n\n const createDocumentRewriter = (context?: APIContext | undefined): IslandRewriter => {\n const emittedLinks = new Set<string>();\n const registeredComponents = new Set<string>();\n let runtimeInjected = false;\n\n return createIslandRewriter((attrs) => {\n const componentUrl = attrs['component-url'];\n\n if (!componentUrl) {\n return null;\n }\n\n const component = resolve(componentUrl);\n\n if (!component) {\n return null;\n }\n\n const rendererUrl = attrs['renderer-url'] || null;\n const renderer = rendererUrl ? resolve(rendererUrl) : null;\n\n const closureUrls = (closure: (fileName: string) => string[]): string[] => {\n const urls = new Set([componentUrl, ...closure(component.fileName).map((f) => component.prefix + f)]);\n\n if (rendererUrl) {\n urls.add(rendererUrl);\n\n for (const f of renderer ? closure(renderer.fileName) : []) {\n urls.add(renderer!.prefix + f);\n }\n }\n\n return [...urls];\n };\n\n const island: IslandInfo = {\n componentUrl,\n rendererUrl,\n client: attrs['client'] || null,\n staticClosure: closureUrls(graph.staticClosure),\n fullClosure: closureUrls(graph.fullClosure),\n };\n\n const emissions: IslandEmission[] = [{ links: island.staticClosure }];\n\n for (const emitter of getIslandEmitters()) {\n try {\n const emission = emitter(island, context);\n\n if (emission) {\n emissions.push(emission);\n }\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error, componentUrl }, 'island emitter failed');\n }\n }\n\n const links = [...new Set(emissions.flatMap((e) => e.links ?? []))];\n const html = emissions.map((e) => e.html ?? '').join('');\n const directive = (island.client ?? '').replace(/-x$/, '');\n\n if (IMMEDIATE_DIRECTIVES.has(directive)) {\n const fresh = links.filter((url) => !emittedLinks.has(url));\n\n for (const url of fresh) {\n emittedLinks.add(url);\n }\n\n const prepend =\n html +\n fresh.map((url) => `<link rel=\"modulepreload\" fetchpriority=\"low\" href=\"${encodeAttribute(url)}\">`).join('');\n\n return { prepend: prepend || undefined };\n }\n\n if (registeredComponents.has(componentUrl)) {\n return { prepend: html || undefined };\n }\n\n registeredComponents.add(componentUrl);\n\n const runtime = runtimeInjected\n ? ''\n : `<script type=\"module\" src=\"${encodeAttribute(component.prefix + manifest.runtime)}\"></script>`;\n\n runtimeInjected = true;\n\n const register = `<script>(self.${PRELOAD_GLOBAL}??={})[${jsonForScript(componentUrl)}]=${jsonForScript(links)};</script>`;\n\n return { prepend: runtime + register + html || undefined };\n });\n };\n\n return { createDocumentRewriter };\n}\n\nexport type PageTransformOptions = {\n /** the islands rewriter for this document, when preloading is on (prod with a manifest) */\n rewriter?: IslandRewriter | undefined;\n /** scripts inserted right after the opening `<head>` tag — buffers the response */\n heads: string[];\n /** script factories invoked after the rewriter finished, results appended at stream end */\n ends: (() => string | null)[];\n};\n\n/**\n * The single streaming pass over an html page response: chunks go through the\n * islands rewriter (when present), head content is inserted right after the\n * opening `<head>` tag (which requires buffering the whole document — head\n * content is dev-style delivery, where throughput is irrelevant), and end\n * factories run last, strictly after every island passed the rewriter.\n */\nexport function createPageTransformStream(options: PageTransformOptions): TransformStream<Uint8Array, Uint8Array> {\n const { rewriter, heads, ends } = options;\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n const buffered = heads.length > 0 ? ([] as string[]) : null;\n\n const enqueue = (controller: TransformStreamDefaultController<Uint8Array>, text: string): void => {\n if (text) {\n controller.enqueue(encoder.encode(text));\n }\n };\n\n return new TransformStream({\n transform(chunk, controller) {\n let text = decoder.decode(chunk, { stream: true });\n\n if (rewriter) {\n text = rewriter.write(text);\n }\n\n if (buffered) {\n buffered.push(text);\n } else {\n enqueue(controller, text);\n }\n },\n async flush(controller) {\n let tail = decoder.decode();\n\n if (rewriter) {\n tail = (tail ? rewriter.write(tail) : '') + (await rewriter.end());\n }\n\n if (buffered) {\n const html = buffered.join('') + tail;\n // nothing but the doctype, comments and <html> can precede <head>, so the\n // first match cannot sit inside script raw text\n const head = /<head[^>]*>/i.exec(html);\n const at = head ? head.index + head[0].length : 0;\n\n enqueue(controller, html.slice(0, at) + heads.join('') + html.slice(at));\n } else {\n enqueue(controller, tail);\n }\n\n for (const end of ends) {\n try {\n enqueue(controller, end() ?? '');\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error }, 'document emitter failed');\n }\n }\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-D0uMBi2M.d.ts","names":[],"sources":["../src/lifecycle/types.ts"],"mappings":";UAAiB
|
|
1
|
+
{"version":3,"file":"types-D0uMBi2M.d.ts","names":[],"sources":["../src/lifecycle/types.ts"],"mappings":";UAAiB;;EAEf;;EAEA;;EAEA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astroscope/node",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Opinionated, cloud-friendly Node adapter for Astro: boot lifecycle, health probes, request logging, telemetry, CSRF and static serving run as plain code around server.listen()",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,6 +51,23 @@
|
|
|
51
51
|
"types": "./dist/dev-middleware-entrypoint.d.ts",
|
|
52
52
|
"import": "./dist/dev-middleware-entrypoint.js"
|
|
53
53
|
},
|
|
54
|
+
"./image-endpoint": {
|
|
55
|
+
"types": "./dist/image-endpoint.d.ts",
|
|
56
|
+
"import": "./dist/image-endpoint.js",
|
|
57
|
+
"default": "./dist/image-endpoint.js"
|
|
58
|
+
},
|
|
59
|
+
"./image-service": {
|
|
60
|
+
"types": "./dist/image-service.d.ts",
|
|
61
|
+
"import": "./dist/image-service.js"
|
|
62
|
+
},
|
|
63
|
+
"./islands": {
|
|
64
|
+
"types": "./dist/islands.d.ts",
|
|
65
|
+
"import": "./dist/islands.js"
|
|
66
|
+
},
|
|
67
|
+
"./islands-middleware": {
|
|
68
|
+
"types": "./dist/islands-middleware-entrypoint.d.ts",
|
|
69
|
+
"import": "./dist/islands-middleware-entrypoint.js"
|
|
70
|
+
},
|
|
54
71
|
"./route-middleware": {
|
|
55
72
|
"types": "./dist/route-middleware-entrypoint.d.ts",
|
|
56
73
|
"import": "./dist/route-middleware-entrypoint.js"
|
|
@@ -82,23 +99,26 @@
|
|
|
82
99
|
},
|
|
83
100
|
"homepage": "https://github.com/entwico/astroscope/tree/main/packages/node#readme",
|
|
84
101
|
"dependencies": {
|
|
85
|
-
"@
|
|
86
|
-
"@entwico/
|
|
102
|
+
"@astrojs/compiler-rs": "^0.4.0",
|
|
103
|
+
"@entwico/dash": "^1.3.0",
|
|
104
|
+
"@entwico/health-probes": "^1.1.2",
|
|
87
105
|
"@opentelemetry/api": "^1.9.1",
|
|
88
|
-
"@opentelemetry/exporter-prometheus": "^0.
|
|
106
|
+
"@opentelemetry/exporter-prometheus": "^0.221.0",
|
|
89
107
|
"@opentelemetry/host-metrics": "^0.39.0",
|
|
90
|
-
"@opentelemetry/instrumentation-runtime-node": "^0.
|
|
91
|
-
"@opentelemetry/instrumentation-undici": "^0.
|
|
92
|
-
"@opentelemetry/sdk-node": "^0.
|
|
93
|
-
"acorn": "^8.
|
|
94
|
-
"magic-string": "^
|
|
108
|
+
"@opentelemetry/instrumentation-runtime-node": "^0.34.0",
|
|
109
|
+
"@opentelemetry/instrumentation-undici": "^0.31.0",
|
|
110
|
+
"@opentelemetry/sdk-node": "^0.221.0",
|
|
111
|
+
"acorn": "^8.18.0",
|
|
112
|
+
"magic-string": "^1.2.2",
|
|
113
|
+
"parse5-html-rewriting-stream": "^8.0.1",
|
|
95
114
|
"pino": "^10.3.1",
|
|
96
115
|
"send": "^1.2.1"
|
|
97
116
|
},
|
|
98
117
|
"devDependencies": {
|
|
99
118
|
"@types/send": "^1.2.1",
|
|
100
|
-
"astro": "^7.
|
|
101
|
-
"
|
|
119
|
+
"astro": "^7.2.6",
|
|
120
|
+
"happy-dom": "^20.11.6",
|
|
121
|
+
"tsdown": "^0.22.14",
|
|
102
122
|
"typescript": "^6.0.3"
|
|
103
123
|
},
|
|
104
124
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"construct-DgB-jR0a.d.ts","names":[],"sources":["../src/observability/log/construct.ts"],"mappings":";;;;;AASA;;;KAAY,oBAAA,GAAuB,aAAA,KAAkB,GAAA;EAAO,GAAA;AAAA,MAAmB,aAAA,GAAgB,OAAA,CAAQ,aAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events-CUzQ2_cp.d.ts","names":[],"sources":["../src/lifecycle/events.ts"],"mappings":";;;KAEY,aAAA;AAAA,KAEA,gBAAA,IAAoB,OAAA,EAAS,WAAA,KAAgB,OAAO;AAFhE;;;AAAA,iBAyBgB,EAAA,CAAG,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,gBAAgB;AAzBzC;AAEzB;;AAFyB,iBAwCT,GAAA,CAAI,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,gBAAgB;;;;iBAS7C,IAAA,CAAK,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,WAAA,GAAc,OAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"excludes-DLF3A_Cf.d.ts","names":[],"sources":["../src/excludes/excludes.ts"],"mappings":";;;;;;AAQA;;;KAAY,cAAA,GAAiB,OAAO,CAAC,aAAA,GAAgB,KAAA;;;;cAKxC,YAAA,EAAc,cAAc;AALyB;AAKlE;;AALkE,cAgBrD,qBAAA,EAAuB,cAAc;;AAXT;AAWzC;cAKa,eAAA,EAAiB,cAAc;;;AALM;AAKlD;;;;AAA4C;AAwB5C;;;;AAAiD;AAKjD;;cALa,oBAAA,EAAsB,cAAc;;;;iBAKjC,aAAA,CACd,GAAA,EAAK,UAAA,EACL,OAAA,WAAkB,aAAA,OAAoB,OAAA,EAAS,UAAA;;;;;;;;;AAAmC;AA4BpF;;;;;;;;iBAAgB,YAAA,CACd,UAAA,EAAY,iBAAA,EACZ,OAAA,WAAkB,aAAA,OAAoB,OAAA,EAAS,UAAA,gBAC9C,iBAAA"}
|