@statikapi/adapter-cf
Advanced tools
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
+3
-10
@@ -7,3 +7,3 @@ #!/usr/bin/env node | ||
| import { bundle } from '../src/node/bundle.js'; | ||
| import { loadLocalEnv, startPreviewServer } from '../src/node/preview.js'; | ||
| import { loadLocalEnv, refreshPreviewPrivateOutputs, startPreviewServer } from '../src/node/preview.js'; | ||
@@ -352,11 +352,4 @@ function parseArgs(argv) { | ||
| try { | ||
| const res = await fetch(new URL('/', workerOrigin), { | ||
| method: 'POST', | ||
| headers: { | ||
| authorization: `Bearer ${buildToken}`, | ||
| 'content-type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({}), | ||
| }); | ||
| if (res.ok) { | ||
| const refreshed = await refreshPreviewPrivateOutputs(workerOrigin, {}, { buildToken }); | ||
| if (refreshed) { | ||
| console.log(`statikapi-cf dev → refreshed private outputs (${reason})`); | ||
@@ -363,0 +356,0 @@ return; |
+1
-1
| { | ||
| "name": "@statikapi/adapter-cf", | ||
| "version": "1.0.0-rc.1", | ||
| "version": "1.0.0-rc.2", | ||
| "type": "module", | ||
@@ -5,0 +5,0 @@ "bin": { |
+90
-15
@@ -309,3 +309,3 @@ import fs from 'node:fs/promises'; | ||
| if (concreteRoute === '/') { | ||
| return prefix + (useIndexJson ? 'index.json' : 'index.json'); | ||
| return prefix + (useIndexJson ? 'index.json' : 'index'); | ||
| } | ||
@@ -315,5 +315,16 @@ | ||
| if (useIndexJson) return prefix + clean + '/index.json'; | ||
| return prefix + clean + '.json'; | ||
| return prefix + clean + '/index'; | ||
| } | ||
| function publicDisplayKeyForRoute(concreteRoute, useIndexJson) { | ||
| const prefix = 'public/'; | ||
| if (concreteRoute === '/') { | ||
| return prefix + (useIndexJson ? 'index.json' : 'index'); | ||
| } | ||
| const clean = concreteRoute.replace(/^\/+/, ''); | ||
| if (useIndexJson) return prefix + clean + '/index.json'; | ||
| return prefix + clean; | ||
| } | ||
| async function textHash(text) { | ||
@@ -323,7 +334,7 @@ return createHash('sha256').update(text).digest('hex'); | ||
| function publicManifestEntryFor(sourceRoute, concreteRoute, key, body) { | ||
| function publicManifestEntryFor(sourceRoute, concreteRoute, filePath, body) { | ||
| return { | ||
| route: concreteRoute === '/' ? '/public' : '/public' + concreteRoute, | ||
| srcRoute: sourceRoute, | ||
| filePath: key, | ||
| filePath, | ||
| bytes: new TextEncoder().encode(body).length, | ||
@@ -350,8 +361,9 @@ mtime: Date.now(), | ||
| const body = JSON.stringify(output.value, null, 2) + '\n'; | ||
| const key = outputKeyForRoute(output.route, useIndexJson, true); | ||
| const target = path.join(outRoot, key); | ||
| const assetKey = outputKeyForRoute(output.route, useIndexJson, true); | ||
| const displayKey = publicDisplayKeyForRoute(output.route, useIndexJson); | ||
| const target = path.join(outRoot, assetKey); | ||
| await fs.mkdir(path.dirname(target), { recursive: true }); | ||
| await fs.writeFile(target, body, 'utf8'); | ||
| const manifestEntry = publicManifestEntryFor(entry.route, output.route, key, body); | ||
| const manifestEntry = publicManifestEntryFor(entry.route, output.route, displayKey, body); | ||
| manifestEntry.hash = await textHash(body); | ||
@@ -834,2 +846,6 @@ const owner = owners.get(manifestEntry.route); | ||
| if (!normalized) return '/'; | ||
| } else { | ||
| if (normalized === '/index') return '/'; | ||
| normalized = normalized.replace(/\\/index$/, ''); | ||
| if (!normalized) return '/'; | ||
| } | ||
@@ -850,3 +866,3 @@ | ||
| if (concreteRoute === '/') { | ||
| return prefix + 'index.json'; | ||
| return prefix + (useIndexJson(env) ? 'index.json' : 'index'); | ||
| } | ||
@@ -856,3 +872,3 @@ | ||
| if (useIndexJson(env)) return prefix + clean + '/index.json'; | ||
| return prefix + clean + '.json'; | ||
| return prefix + clean; | ||
| } | ||
@@ -865,3 +881,3 @@ | ||
| } | ||
| return useIndexJson(env) ? [base, base + '/index.json'] : [base, base + '.json']; | ||
| return useIndexJson(env) ? [base, base + '/index.json'] : [base, base + '/index']; | ||
| } | ||
@@ -871,7 +887,7 @@ | ||
| if (concreteRoute === '/') { | ||
| return useIndexJson(env) ? ['/', '/index.json'] : ['/', '/index.json']; | ||
| return useIndexJson(env) ? ['/', '/index.json'] : ['/', '/index']; | ||
| } | ||
| return useIndexJson(env) | ||
| ? [concreteRoute, concreteRoute + '/index.json'] | ||
| : [concreteRoute, concreteRoute + '.json']; | ||
| : [concreteRoute]; | ||
| } | ||
@@ -912,9 +928,9 @@ | ||
| if (normalized === '/') { | ||
| return useIndexJson(env) ? '/public/index.json' : '/public/index.json'; | ||
| return useIndexJson(env) ? '/public/index.json' : '/public/index'; | ||
| } | ||
| return useIndexJson(env) ? '/public' + normalized + '/index.json' : '/public' + normalized + '.json'; | ||
| return useIndexJson(env) ? '/public' + normalized + '/index.json' : '/public' + normalized + '/index'; | ||
| } | ||
| function publicManifestAssetPath(env) { | ||
| return useIndexJson(env) ? '/public/_manifest/index.json' : '/public/_manifest.json'; | ||
| return useIndexJson(env) ? '/public/_manifest/index.json' : '/public/_manifest/index'; | ||
| } | ||
@@ -1203,2 +1219,60 @@ | ||
| function isLoopbackRequest(req) { | ||
| try { | ||
| const { hostname } = new URL(req.url); | ||
| return ( | ||
| hostname === '127.0.0.1' || | ||
| hostname === 'localhost' || | ||
| hostname === '::1' || | ||
| hostname === '[::1]' | ||
| ); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| async function handlePreviewBuild(req, env) { | ||
| if (!isLoopbackRequest(req)) { | ||
| return new Response('Not found', { status: 404 }); | ||
| } | ||
| if (!requireBuildAuth(req, env)) { | ||
| return new Response('unauthorized', { status: 401 }); | ||
| } | ||
| const body = await req.json().catch(() => ({})); | ||
| const pretty = body.pretty ?? DEFAULT_PRETTY; | ||
| const manifest = []; | ||
| const expanded = await expandAllRoutes(REGISTRY); | ||
| const owners = new Map(); | ||
| let writtenBytes = 0; | ||
| for (const sourceEntry of expanded) { | ||
| const built = await buildSourceOutputs(sourceEntry, env, pretty); | ||
| if (built.error) return built.error; | ||
| writtenBytes += built.writtenBytes; | ||
| for (const entry of built.manifestEntries) { | ||
| addManifestEntry(manifest, entry, owners); | ||
| } | ||
| for (const target of built.purgeTargets) { | ||
| await purgeCacheForPath(new URL(req.url).origin, target); | ||
| } | ||
| } | ||
| manifest.sort((a, b) => a.route.localeCompare(b.route)); | ||
| await writeManifest(env, manifest); | ||
| return new Response( | ||
| JSON.stringify({ | ||
| ok: true, | ||
| files: manifest.length, | ||
| bytes: writtenBytes, | ||
| preview: true, | ||
| updated: true, | ||
| }), | ||
| { headers: { 'content-type': 'application/json' } } | ||
| ); | ||
| } | ||
| async function findManifestEntryForRequest(pathname, env, isPublicRoute) { | ||
@@ -1266,2 +1340,3 @@ const manifest = isPublicRoute ? PUBLIC_MANIFEST : await readManifest(env); | ||
| if (req.method === 'POST') { | ||
| if (url.pathname === '/_preview/build') return handlePreviewBuild(req, env); | ||
| if (url.pathname === '/') return handleBuild(req, env); | ||
@@ -1268,0 +1343,0 @@ return handleBuildRoute(req, env, url.pathname); |
+37
-1
@@ -18,2 +18,3 @@ import http from 'node:http'; | ||
| const localEnv = await loadLocalEnv(cwd); | ||
| const buildToken = await readBuildToken(cwd, localEnv); | ||
| const uiMeta = await loadUiMeta(cwd, workerOrigin, localEnv); | ||
@@ -44,2 +45,3 @@ const sseClients = new Set(); | ||
| if (pathname === '/ui/index' && req.method === 'GET') { | ||
| await refreshPreviewPrivateOutputs(workerOrigin, localEnv, { buildToken }).catch(() => {}); | ||
| const manifest = await fetchManifest(workerOrigin, uiMeta, localEnv); | ||
@@ -211,2 +213,23 @@ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' }); | ||
| export async function refreshPreviewPrivateOutputs(workerOrigin, localEnv = {}, options = {}) { | ||
| const buildToken = options.buildToken || localEnv.STATIK_BUILD_TOKEN || process.env.STATIK_BUILD_TOKEN; | ||
| if (!buildToken) return false; | ||
| const res = await fetch(new URL('/_preview/build', workerOrigin), { | ||
| method: 'POST', | ||
| headers: { | ||
| authorization: `Bearer ${buildToken}`, | ||
| 'content-type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({}), | ||
| cache: 'no-store', | ||
| }); | ||
| if (!res.ok) { | ||
| throw new Error(`preview private build failed: ${res.status}`); | ||
| } | ||
| return true; | ||
| } | ||
| function privateAuthHeaderName(localEnv) { | ||
@@ -239,2 +262,15 @@ return localEnv.STATIK_PRIVATE_AUTH_HEADER_NAME || process.env.STATIK_PRIVATE_AUTH_HEADER_NAME; | ||
| async function readBuildToken(cwd, localEnv = {}) { | ||
| if (localEnv.STATIK_BUILD_TOKEN) return localEnv.STATIK_BUILD_TOKEN; | ||
| const wranglerPath = path.join(cwd, 'wrangler.toml'); | ||
| try { | ||
| const raw = await fs.readFile(wranglerPath, 'utf8'); | ||
| return ( | ||
| readTomlVar(raw, 'STATIK_BUILD_TOKEN') || process.env.STATIK_BUILD_TOKEN || '' | ||
| ); | ||
| } catch { | ||
| return process.env.STATIK_BUILD_TOKEN || ''; | ||
| } | ||
| } | ||
| async function readUseIndexJson(cwd) { | ||
@@ -270,3 +306,3 @@ const wranglerPath = path.join(cwd, 'wrangler.toml'); | ||
| function publicManifestPathFor(useIndexJson) { | ||
| return useIndexJson ? '/public/_manifest/index.json' : '/public/_manifest.json'; | ||
| return useIndexJson ? '/public/_manifest/index.json' : '/public/_manifest'; | ||
| } | ||
@@ -273,0 +309,0 @@ |
+1
-1
@@ -20,3 +20,3 @@ <!doctype html> | ||
| </script> | ||
| <script type="module" crossorigin src="/_ui/assets/index-DQxY5SSL.js"></script> | ||
| <script type="module" crossorigin src="/_ui/assets/index-B1KQNyxK.js"></script> | ||
| <link rel="stylesheet" crossorigin href="/_ui/assets/index-dGdl_f78.css"> | ||
@@ -23,0 +23,0 @@ </head> |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1263944
0.38%3113
3.01%7
-12.5%14
16.67%