@gigadrive/network-config 4.3.1 → 4.3.3

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.
@@ -157,11 +157,17 @@ var getRuntimeCacheTagState = async (kind, tags) => {
157
157
  var registerResumeRewarm = () => {
158
158
  const onGigadrive = process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;
159
159
  if (!onGigadrive) return;
160
- process.on("SIGUSR2", () => {
161
- cachedToken = void 0;
162
- if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
163
- void readRuntimeCache("warmup", "__resume__");
164
- });
160
+ const runtimeProcess = Reflect.get(globalThis, "process");
161
+ const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, "on");
162
+ if (typeof addSignalListener !== "function") return;
163
+ Reflect.apply(addSignalListener, runtimeProcess, [
164
+ "SIGUSR2",
165
+ () => {
166
+ cachedToken = void 0;
167
+ if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
168
+ void readRuntimeCache("warmup", "__resume__");
169
+ }
170
+ ]);
165
171
  };
166
172
  registerResumeRewarm();
167
173
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-cache-components-handler.ts","../src/nextjs-runtime-cache-client.ts"],"sourcesContent":["import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\ninterface CacheComponentEntry {\n value: ReadableStream<Uint8Array>;\n tags: string[];\n stale: number;\n timestamp: number;\n expire: number;\n revalidate: number;\n}\n\ninterface SerializedCacheComponentEntry extends Omit<CacheComponentEntry, 'value'> {\n value: Uint8Array;\n}\n\nconst isSerializedCacheComponentEntry = (value: unknown): value is SerializedCacheComponentEntry => {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Partial<SerializedCacheComponentEntry>;\n return (\n entry.value instanceof Uint8Array &&\n Array.isArray(entry.tags) &&\n entry.tags.every((tag) => typeof tag === 'string') &&\n typeof entry.stale === 'number' &&\n typeof entry.timestamp === 'number' &&\n typeof entry.expire === 'number' &&\n typeof entry.revalidate === 'number'\n );\n};\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst buildEntries = new Map<string, SerializedCacheComponentEntry>();\n\nconst streamToBytes = async (stream: ReadableStream<Uint8Array>): Promise<Uint8Array> => {\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = stream.getReader();\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n chunks.push(result.value);\n size += result.value.byteLength;\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n};\n\n/** Shared Network cache handler for Next.js Cache Components and `use cache`. */\nconst cacheHandler = {\n async get(cacheKey: string, softTags: string[]): Promise<CacheComponentEntry | undefined> {\n await pendingWrites.get(cacheKey);\n const value =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? buildEntries.get(cacheKey)\n : await readRuntimeCache('component', cacheKey);\n if (!isSerializedCacheComponentEntry(value)) return undefined;\n const tagState =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? { stale: 0, expired: 0 }\n : await getRuntimeCacheTagState('component', [...new Set([...value.tags, ...softTags])]);\n if (tagState.expired > value.timestamp) return undefined;\n return {\n ...value,\n ...(tagState.stale > value.timestamp ? { revalidate: -1 } : {}),\n value: new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(value.value);\n controller.close();\n },\n }),\n };\n },\n\n async set(cacheKey: string, pendingEntry: Promise<CacheComponentEntry>): Promise<void> {\n const write = (async () => {\n const entry = await pendingEntry;\n const value = await streamToBytes(entry.value);\n const serializedEntry = { ...entry, value };\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n buildEntries.set(cacheKey, serializedEntry);\n } else {\n await writeRuntimeCache('component', cacheKey, serializedEntry, entry.tags);\n }\n })();\n pendingWrites.set(cacheKey, write);\n try {\n await write;\n } finally {\n if (pendingWrites.get(cacheKey) === write) pendingWrites.delete(cacheKey);\n }\n },\n\n async refreshTags(): Promise<void> {},\n\n getExpiration(): Promise<number> {\n return Promise.resolve(Infinity);\n },\n\n async updateTags(tags: string[], durations?: { expire?: number }): Promise<void> {\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n for (const [key, entry] of buildEntries) {\n if (entry.tags.some((tag) => tags.includes(tag))) buildEntries.delete(key);\n }\n return;\n }\n return revalidateRuntimeCacheTags('component', tags, durations);\n },\n};\n\nexport default cacheHandler;\n","interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n process.on('SIGUSR2', () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n });\n};\nregisterResumeRewarm();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/nextjs-cache-components-handler.ts","../src/nextjs-runtime-cache-client.ts"],"sourcesContent":["import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\ninterface CacheComponentEntry {\n value: ReadableStream<Uint8Array>;\n tags: string[];\n stale: number;\n timestamp: number;\n expire: number;\n revalidate: number;\n}\n\ninterface SerializedCacheComponentEntry extends Omit<CacheComponentEntry, 'value'> {\n value: Uint8Array;\n}\n\nconst isSerializedCacheComponentEntry = (value: unknown): value is SerializedCacheComponentEntry => {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Partial<SerializedCacheComponentEntry>;\n return (\n entry.value instanceof Uint8Array &&\n Array.isArray(entry.tags) &&\n entry.tags.every((tag) => typeof tag === 'string') &&\n typeof entry.stale === 'number' &&\n typeof entry.timestamp === 'number' &&\n typeof entry.expire === 'number' &&\n typeof entry.revalidate === 'number'\n );\n};\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst buildEntries = new Map<string, SerializedCacheComponentEntry>();\n\nconst streamToBytes = async (stream: ReadableStream<Uint8Array>): Promise<Uint8Array> => {\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = stream.getReader();\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n chunks.push(result.value);\n size += result.value.byteLength;\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n};\n\n/** Shared Network cache handler for Next.js Cache Components and `use cache`. */\nconst cacheHandler = {\n async get(cacheKey: string, softTags: string[]): Promise<CacheComponentEntry | undefined> {\n await pendingWrites.get(cacheKey);\n const value =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? buildEntries.get(cacheKey)\n : await readRuntimeCache('component', cacheKey);\n if (!isSerializedCacheComponentEntry(value)) return undefined;\n const tagState =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? { stale: 0, expired: 0 }\n : await getRuntimeCacheTagState('component', [...new Set([...value.tags, ...softTags])]);\n if (tagState.expired > value.timestamp) return undefined;\n return {\n ...value,\n ...(tagState.stale > value.timestamp ? { revalidate: -1 } : {}),\n value: new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(value.value);\n controller.close();\n },\n }),\n };\n },\n\n async set(cacheKey: string, pendingEntry: Promise<CacheComponentEntry>): Promise<void> {\n const write = (async () => {\n const entry = await pendingEntry;\n const value = await streamToBytes(entry.value);\n const serializedEntry = { ...entry, value };\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n buildEntries.set(cacheKey, serializedEntry);\n } else {\n await writeRuntimeCache('component', cacheKey, serializedEntry, entry.tags);\n }\n })();\n pendingWrites.set(cacheKey, write);\n try {\n await write;\n } finally {\n if (pendingWrites.get(cacheKey) === write) pendingWrites.delete(cacheKey);\n }\n },\n\n async refreshTags(): Promise<void> {},\n\n getExpiration(): Promise<number> {\n return Promise.resolve(Infinity);\n },\n\n async updateTags(tags: string[], durations?: { expire?: number }): Promise<void> {\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n for (const [key, entry] of buildEntries) {\n if (entry.tags.some((tag) => tags.includes(tag))) buildEntries.delete(key);\n }\n return;\n }\n return revalidateRuntimeCacheTags('component', tags, durations);\n },\n};\n\nexport default cacheHandler;\n","interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n\n // This module is shared by Node and Edge cache-handler bundles. Next.js 16.2\n // rejects a statically analyzable `process.on` call while collecting Edge\n // route data, even though the listener only runs inside the Node runtime.\n // Resolve the optional Node signal API reflectively so Edge builds can load\n // the shared client while Node deployments retain resume rewarming.\n const runtimeProcess = Reflect.get(globalThis, 'process') as NodeJS.Process | undefined;\n const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, 'on');\n if (typeof addSignalListener !== 'function') return;\n\n Reflect.apply(addSignalListener, runtimeProcess, [\n 'SIGUSR2',\n () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n },\n ]);\n};\nregisterResumeRewarm();\n"],"mappings":"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","names":[]}
@@ -131,11 +131,17 @@ var getRuntimeCacheTagState = async (kind, tags) => {
131
131
  var registerResumeRewarm = () => {
132
132
  const onGigadrive = process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;
133
133
  if (!onGigadrive) return;
134
- process.on("SIGUSR2", () => {
135
- cachedToken = void 0;
136
- if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
137
- void readRuntimeCache("warmup", "__resume__");
138
- });
134
+ const runtimeProcess = Reflect.get(globalThis, "process");
135
+ const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, "on");
136
+ if (typeof addSignalListener !== "function") return;
137
+ Reflect.apply(addSignalListener, runtimeProcess, [
138
+ "SIGUSR2",
139
+ () => {
140
+ cachedToken = void 0;
141
+ if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
142
+ void readRuntimeCache("warmup", "__resume__");
143
+ }
144
+ ]);
139
145
  };
140
146
  registerResumeRewarm();
141
147
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-runtime-cache-client.ts","../src/nextjs-cache-components-handler.ts"],"sourcesContent":["interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n process.on('SIGUSR2', () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n });\n};\nregisterResumeRewarm();\n","import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\ninterface CacheComponentEntry {\n value: ReadableStream<Uint8Array>;\n tags: string[];\n stale: number;\n timestamp: number;\n expire: number;\n revalidate: number;\n}\n\ninterface SerializedCacheComponentEntry extends Omit<CacheComponentEntry, 'value'> {\n value: Uint8Array;\n}\n\nconst isSerializedCacheComponentEntry = (value: unknown): value is SerializedCacheComponentEntry => {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Partial<SerializedCacheComponentEntry>;\n return (\n entry.value instanceof Uint8Array &&\n Array.isArray(entry.tags) &&\n entry.tags.every((tag) => typeof tag === 'string') &&\n typeof entry.stale === 'number' &&\n typeof entry.timestamp === 'number' &&\n typeof entry.expire === 'number' &&\n typeof entry.revalidate === 'number'\n );\n};\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst buildEntries = new Map<string, SerializedCacheComponentEntry>();\n\nconst streamToBytes = async (stream: ReadableStream<Uint8Array>): Promise<Uint8Array> => {\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = stream.getReader();\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n chunks.push(result.value);\n size += result.value.byteLength;\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n};\n\n/** Shared Network cache handler for Next.js Cache Components and `use cache`. */\nconst cacheHandler = {\n async get(cacheKey: string, softTags: string[]): Promise<CacheComponentEntry | undefined> {\n await pendingWrites.get(cacheKey);\n const value =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? buildEntries.get(cacheKey)\n : await readRuntimeCache('component', cacheKey);\n if (!isSerializedCacheComponentEntry(value)) return undefined;\n const tagState =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? { stale: 0, expired: 0 }\n : await getRuntimeCacheTagState('component', [...new Set([...value.tags, ...softTags])]);\n if (tagState.expired > value.timestamp) return undefined;\n return {\n ...value,\n ...(tagState.stale > value.timestamp ? { revalidate: -1 } : {}),\n value: new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(value.value);\n controller.close();\n },\n }),\n };\n },\n\n async set(cacheKey: string, pendingEntry: Promise<CacheComponentEntry>): Promise<void> {\n const write = (async () => {\n const entry = await pendingEntry;\n const value = await streamToBytes(entry.value);\n const serializedEntry = { ...entry, value };\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n buildEntries.set(cacheKey, serializedEntry);\n } else {\n await writeRuntimeCache('component', cacheKey, serializedEntry, entry.tags);\n }\n })();\n pendingWrites.set(cacheKey, write);\n try {\n await write;\n } finally {\n if (pendingWrites.get(cacheKey) === write) pendingWrites.delete(cacheKey);\n }\n },\n\n async refreshTags(): Promise<void> {},\n\n getExpiration(): Promise<number> {\n return Promise.resolve(Infinity);\n },\n\n async updateTags(tags: string[], durations?: { expire?: number }): Promise<void> {\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n for (const [key, entry] of buildEntries) {\n if (entry.tags.some((tag) => tags.includes(tag))) buildEntries.delete(key);\n }\n return;\n }\n return revalidateRuntimeCacheTags('component', tags, durations);\n },\n};\n\nexport default cacheHandler;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/nextjs-runtime-cache-client.ts","../src/nextjs-cache-components-handler.ts"],"sourcesContent":["interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n\n // This module is shared by Node and Edge cache-handler bundles. Next.js 16.2\n // rejects a statically analyzable `process.on` call while collecting Edge\n // route data, even though the listener only runs inside the Node runtime.\n // Resolve the optional Node signal API reflectively so Edge builds can load\n // the shared client while Node deployments retain resume rewarming.\n const runtimeProcess = Reflect.get(globalThis, 'process') as NodeJS.Process | undefined;\n const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, 'on');\n if (typeof addSignalListener !== 'function') return;\n\n Reflect.apply(addSignalListener, runtimeProcess, [\n 'SIGUSR2',\n () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n },\n ]);\n};\nregisterResumeRewarm();\n","import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\ninterface CacheComponentEntry {\n value: ReadableStream<Uint8Array>;\n tags: string[];\n stale: number;\n timestamp: number;\n expire: number;\n revalidate: number;\n}\n\ninterface SerializedCacheComponentEntry extends Omit<CacheComponentEntry, 'value'> {\n value: Uint8Array;\n}\n\nconst isSerializedCacheComponentEntry = (value: unknown): value is SerializedCacheComponentEntry => {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Partial<SerializedCacheComponentEntry>;\n return (\n entry.value instanceof Uint8Array &&\n Array.isArray(entry.tags) &&\n entry.tags.every((tag) => typeof tag === 'string') &&\n typeof entry.stale === 'number' &&\n typeof entry.timestamp === 'number' &&\n typeof entry.expire === 'number' &&\n typeof entry.revalidate === 'number'\n );\n};\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst buildEntries = new Map<string, SerializedCacheComponentEntry>();\n\nconst streamToBytes = async (stream: ReadableStream<Uint8Array>): Promise<Uint8Array> => {\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = stream.getReader();\n while (true) {\n const result = await reader.read();\n if (result.done) break;\n chunks.push(result.value);\n size += result.value.byteLength;\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return bytes;\n};\n\n/** Shared Network cache handler for Next.js Cache Components and `use cache`. */\nconst cacheHandler = {\n async get(cacheKey: string, softTags: string[]): Promise<CacheComponentEntry | undefined> {\n await pendingWrites.get(cacheKey);\n const value =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? buildEntries.get(cacheKey)\n : await readRuntimeCache('component', cacheKey);\n if (!isSerializedCacheComponentEntry(value)) return undefined;\n const tagState =\n process.env.GIGADRIVE_NEXT_BUILD === '1'\n ? { stale: 0, expired: 0 }\n : await getRuntimeCacheTagState('component', [...new Set([...value.tags, ...softTags])]);\n if (tagState.expired > value.timestamp) return undefined;\n return {\n ...value,\n ...(tagState.stale > value.timestamp ? { revalidate: -1 } : {}),\n value: new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(value.value);\n controller.close();\n },\n }),\n };\n },\n\n async set(cacheKey: string, pendingEntry: Promise<CacheComponentEntry>): Promise<void> {\n const write = (async () => {\n const entry = await pendingEntry;\n const value = await streamToBytes(entry.value);\n const serializedEntry = { ...entry, value };\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n buildEntries.set(cacheKey, serializedEntry);\n } else {\n await writeRuntimeCache('component', cacheKey, serializedEntry, entry.tags);\n }\n })();\n pendingWrites.set(cacheKey, write);\n try {\n await write;\n } finally {\n if (pendingWrites.get(cacheKey) === write) pendingWrites.delete(cacheKey);\n }\n },\n\n async refreshTags(): Promise<void> {},\n\n getExpiration(): Promise<number> {\n return Promise.resolve(Infinity);\n },\n\n async updateTags(tags: string[], durations?: { expire?: number }): Promise<void> {\n if (process.env.GIGADRIVE_NEXT_BUILD === '1') {\n for (const [key, entry] of buildEntries) {\n if (entry.tags.some((tag) => tags.includes(tag))) buildEntries.delete(key);\n }\n return;\n }\n return revalidateRuntimeCacheTags('component', tags, durations);\n },\n};\n\nexport default cacheHandler;\n"],"mappings":"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","names":[]}
@@ -168,11 +168,17 @@ var getRuntimeCacheTagState = async (kind, tags) => {
168
168
  var registerResumeRewarm = () => {
169
169
  const onGigadrive = process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;
170
170
  if (!onGigadrive) return;
171
- process.on("SIGUSR2", () => {
172
- cachedToken = void 0;
173
- if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
174
- void readRuntimeCache("warmup", "__resume__");
175
- });
171
+ const runtimeProcess = Reflect.get(globalThis, "process");
172
+ const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, "on");
173
+ if (typeof addSignalListener !== "function") return;
174
+ Reflect.apply(addSignalListener, runtimeProcess, [
175
+ "SIGUSR2",
176
+ () => {
177
+ cachedToken = void 0;
178
+ if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
179
+ void readRuntimeCache("warmup", "__resume__");
180
+ }
181
+ ]);
176
182
  };
177
183
  registerResumeRewarm();
178
184
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-cache-handler.ts","../src/nextjs-runtime-cache-client.ts"],"sourcesContent":["import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\n/** Header Next uses to carry an entry's cache tags (comma separated). */\nconst NEXT_CACHE_TAGS_HEADER = 'x-next-cache-tags';\n\ninterface IncrementalCacheContext {\n tags?: string[];\n softTags?: string[];\n cacheControl?: unknown;\n kind?: string;\n}\n\ninterface IncrementalCacheEntry {\n lastModified: number;\n value: unknown | null;\n tags?: string[];\n cacheControl?: unknown;\n}\n\n/** Constructor context Next passes to a custom cache handler. */\ninterface CacheHandlerConstructorContext {\n fs?: unknown;\n serverDistDir?: string;\n dev?: boolean;\n flushToDisk?: boolean;\n revalidatedTags?: string[];\n maxMemoryCacheSize?: number;\n _requestHeaders?: unknown;\n fetchCacheKeyPrefix?: string;\n}\n\ninterface FileSystemCacheLike {\n get(key: string, context: IncrementalCacheContext): Promise<IncrementalCacheEntry | null | undefined>;\n}\n\nconst isIncrementalCacheEntry = (value: unknown): value is IncrementalCacheEntry =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Partial<IncrementalCacheEntry>).lastModified === 'number' &&\n 'value' in value;\n\n/**\n * Reads the cache tags carried by a cached value's own headers.\n *\n * Next never populates `context.tags` for APP_PAGE/APP_ROUTE/PAGES — only fetch\n * cache entries carry tags on the context. For route entries the tags live in\n * the cached value's headers under `x-next-cache-tags` as a comma-joined string,\n * so reading them here is what keeps the remote tag index (and therefore\n * `revalidateTag`) working for pages and route handlers.\n */\nconst valueTags = (value: unknown): string[] => {\n const header = (value as { headers?: Record<string, unknown> } | null)?.headers?.[NEXT_CACHE_TAGS_HEADER];\n if (typeof header !== 'string') return [];\n return header\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean);\n};\n\n/** Every tag relevant to an entry: its own, the request's, and the value's headers. */\nconst collectTags = (\n entryTags: string[] | undefined,\n value: unknown,\n context: IncrementalCacheContext = {}\n): string[] => [\n ...new Set([...(entryTags ?? []), ...(context.tags ?? []), ...(context.softTags ?? []), ...valueTags(value)]),\n];\n\nconst isBuildPhase = (): boolean => process.env.GIGADRIVE_NEXT_BUILD === '1';\n\n/**\n * How long a locally cached entry may serve before the remote copy is re-read.\n * Bounds staleness when another instance rewrites the entry; tag-driven\n * invalidation is unaffected because tag state is checked remotely on every\n * read regardless of where the entry bytes came from.\n */\nconst LOCAL_ENTRY_TTL_MS = 5 * 60_000;\nconst LOCAL_CACHE_MAX_ENTRIES = 256;\nconst LOCAL_CACHE_MAX_TOTAL_BYTES = 64 * 1024 * 1024;\nconst LOCAL_CACHE_MAX_ENTRY_BYTES = 8 * 1024 * 1024;\n\ninterface LocalCacheSlot {\n entry: IncrementalCacheEntry;\n cachedAt: number;\n bytes: number;\n}\n\nconst approximateEntryBytes = (entry: IncrementalCacheEntry): number => {\n try {\n return JSON.stringify(entry)?.length ?? LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n } catch {\n // Circular or otherwise unserializable values are never cached locally.\n return LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n }\n};\n\n/**\n * Byte-bounded in-process LRU in front of the remote entry store.\n *\n * The remote store is an HTTP service backed by object storage, so every miss\n * costs a network round trip — and when that store degrades, page renders\n * degrade with it (a production incident showed second-level blob latency\n * turning every render of a cached page into a multi-second response).\n * Serving entry bytes locally removes that dependency from the hot path while\n * the per-read remote tag-state check keeps `revalidateTag` authoritative.\n */\nclass LocalEntryCache {\n private readonly slots = new Map<string, LocalCacheSlot>();\n private totalBytes = 0;\n\n get(key: string): IncrementalCacheEntry | undefined {\n const slot = this.slots.get(key);\n if (!slot) return undefined;\n if (Date.now() - slot.cachedAt > LOCAL_ENTRY_TTL_MS) {\n this.delete(key);\n return undefined;\n }\n // Refresh recency for LRU eviction.\n this.slots.delete(key);\n this.slots.set(key, slot);\n return slot.entry;\n }\n\n set(key: string, entry: IncrementalCacheEntry): void {\n const bytes = approximateEntryBytes(entry);\n if (bytes > LOCAL_CACHE_MAX_ENTRY_BYTES) {\n this.delete(key);\n return;\n }\n this.delete(key);\n this.slots.set(key, { entry, cachedAt: Date.now(), bytes });\n this.totalBytes += bytes;\n while (this.slots.size > LOCAL_CACHE_MAX_ENTRIES || this.totalBytes > LOCAL_CACHE_MAX_TOTAL_BYTES) {\n const oldest = this.slots.keys().next().value;\n if (oldest === undefined) break;\n this.delete(oldest);\n }\n }\n\n delete(key: string): void {\n const slot = this.slots.get(key);\n if (!slot) return;\n this.slots.delete(key);\n this.totalBytes -= slot.bytes;\n }\n\n clear(): void {\n this.slots.clear();\n this.totalBytes = 0;\n }\n}\n\nconst localEntries = new LocalEntryCache();\n\n/** Test-only: the local entry cache is process-wide, so suites must isolate it. */\nexport const clearLocalEntryCacheForTesting = (): void => localEntries.clear();\n\n/** Shared Network cache handler for ISR, server responses, fetches, and image metadata. */\nexport default class GigadriveNextCacheHandler {\n private readonly buildEntries = new Map<string, IncrementalCacheEntry>();\n /**\n * Next's own on-disk reader, pointed at the build output that ships inside the\n * deployment bundle (`writeStandaloneDirectory` recursively copies\n * `.next/server/{app,pages}`). Injecting a `cacheHandler` replaces Next's\n * FileSystemCache outright, which would otherwise strand every build-time\n * prerender and force a cold re-render of each page on first request.\n * Delegating to Next's reader keeps us off its private on-disk format.\n */\n private buildOutputCache?: Promise<FileSystemCacheLike | undefined>;\n private readonly context: CacheHandlerConstructorContext;\n\n constructor(context: CacheHandlerConstructorContext = {}) {\n this.context = context;\n }\n\n /**\n * Loads Next's on-disk reader lazily, memoized across requests. A Next release\n * that moves or renames the module degrades to \"no build-output fallback\" —\n * the remote cache still serves everything that has been regenerated.\n */\n private loadBuildOutputCache(): Promise<FileSystemCacheLike | undefined> {\n this.buildOutputCache ??= (async () => {\n if (!this.context.fs || !this.context.serverDistDir) return undefined;\n try {\n const module: unknown = await import('next/dist/server/lib/incremental-cache/file-system-cache.js');\n // Next ships this as CommonJS, so the constructor sits behind a different\n // number of `default` hops depending on whether this bundle was loaded as\n // CJS or ESM. Unwrap until a callable turns up rather than guessing.\n let candidate: unknown = module;\n for (let hop = 0; hop < 3 && candidate && typeof candidate !== 'function'; hop += 1) {\n candidate = (candidate as { default?: unknown }).default;\n }\n if (typeof candidate !== 'function') return undefined;\n const FileSystemCache = candidate as new (context: CacheHandlerConstructorContext) => FileSystemCacheLike;\n return new FileSystemCache(this.context);\n } catch {\n return undefined;\n }\n })();\n return this.buildOutputCache;\n }\n\n /**\n * Applies remote tag state to an entry.\n *\n * @returns the entry, a stale-marked copy, or `null` when a tag expired.\n */\n private async applyTagState(entry: IncrementalCacheEntry, tags: string[]): Promise<IncrementalCacheEntry | null> {\n if (tags.length === 0) return entry;\n const tagState = await getRuntimeCacheTagState('incremental', tags);\n if (tagState.expired > entry.lastModified) return null;\n return tagState.stale > entry.lastModified ? { ...entry, lastModified: 1 } : entry;\n }\n\n async get(key: string, context: IncrementalCacheContext = {}): Promise<IncrementalCacheEntry | null> {\n if (isBuildPhase()) {\n const buildEntry = this.buildEntries.get(key) ?? null;\n return isIncrementalCacheEntry(buildEntry) ? buildEntry : null;\n }\n\n const local = localEntries.get(key);\n if (local) {\n return this.applyTagState(local, collectTags(local.tags, local.value, context));\n }\n\n const remote = await readRuntimeCache('incremental', key);\n if (isIncrementalCacheEntry(remote)) {\n localEntries.set(key, remote);\n return this.applyTagState(remote, collectTags(remote.tags, remote.value, context));\n }\n\n // Nothing regenerated yet: fall back to the build-time prerender shipped in\n // the bundle. Tag expiry is still resolved against the remote index — Next's\n // reader only knows its own in-process tag manifest, which is always empty\n // here, so trusting it would resurrect content after a `revalidateTag`.\n const buildOutputCache = await this.loadBuildOutputCache();\n const fromDisk = await buildOutputCache?.get(key, context).catch(() => null);\n if (!isIncrementalCacheEntry(fromDisk)) return null;\n return this.applyTagState(fromDisk, collectTags(fromDisk.tags, fromDisk.value, context));\n }\n\n async set(key: string, data: unknown, context: IncrementalCacheContext): Promise<void> {\n const tags = collectTags(undefined, data, context);\n const entry = { lastModified: Date.now(), value: data, tags, cacheControl: context.cacheControl };\n if (isBuildPhase()) {\n this.buildEntries.set(key, entry);\n return;\n }\n localEntries.set(key, entry);\n try {\n await writeRuntimeCache('incremental', key, entry, tags);\n } catch (error) {\n // The local copy would outlive a failed durable write and mask it from\n // this instance for the whole TTL; drop it so reads retry remotely.\n localEntries.delete(key);\n throw error;\n }\n }\n\n async revalidateTag(tags: string | string[], durations?: { expire?: number }): Promise<void> {\n const normalizedTags = Array.isArray(tags) ? tags : [tags];\n if (isBuildPhase()) {\n for (const [key, entry] of this.buildEntries) {\n if (entry.tags?.some((tag) => normalizedTags.includes(tag))) this.buildEntries.delete(key);\n }\n return;\n }\n await revalidateRuntimeCacheTags('incremental', normalizedTags, durations);\n }\n\n resetRequestCache(): void {}\n}\n","interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n process.on('SIGUSR2', () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n });\n};\nregisterResumeRewarm();\n"],"mappings":"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","names":["module"]}
1
+ {"version":3,"sources":["../src/nextjs-cache-handler.ts","../src/nextjs-runtime-cache-client.ts"],"sourcesContent":["import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\n/** Header Next uses to carry an entry's cache tags (comma separated). */\nconst NEXT_CACHE_TAGS_HEADER = 'x-next-cache-tags';\n\ninterface IncrementalCacheContext {\n tags?: string[];\n softTags?: string[];\n cacheControl?: unknown;\n kind?: string;\n}\n\ninterface IncrementalCacheEntry {\n lastModified: number;\n value: unknown | null;\n tags?: string[];\n cacheControl?: unknown;\n}\n\n/** Constructor context Next passes to a custom cache handler. */\ninterface CacheHandlerConstructorContext {\n fs?: unknown;\n serverDistDir?: string;\n dev?: boolean;\n flushToDisk?: boolean;\n revalidatedTags?: string[];\n maxMemoryCacheSize?: number;\n _requestHeaders?: unknown;\n fetchCacheKeyPrefix?: string;\n}\n\ninterface FileSystemCacheLike {\n get(key: string, context: IncrementalCacheContext): Promise<IncrementalCacheEntry | null | undefined>;\n}\n\nconst isIncrementalCacheEntry = (value: unknown): value is IncrementalCacheEntry =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Partial<IncrementalCacheEntry>).lastModified === 'number' &&\n 'value' in value;\n\n/**\n * Reads the cache tags carried by a cached value's own headers.\n *\n * Next never populates `context.tags` for APP_PAGE/APP_ROUTE/PAGES — only fetch\n * cache entries carry tags on the context. For route entries the tags live in\n * the cached value's headers under `x-next-cache-tags` as a comma-joined string,\n * so reading them here is what keeps the remote tag index (and therefore\n * `revalidateTag`) working for pages and route handlers.\n */\nconst valueTags = (value: unknown): string[] => {\n const header = (value as { headers?: Record<string, unknown> } | null)?.headers?.[NEXT_CACHE_TAGS_HEADER];\n if (typeof header !== 'string') return [];\n return header\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean);\n};\n\n/** Every tag relevant to an entry: its own, the request's, and the value's headers. */\nconst collectTags = (\n entryTags: string[] | undefined,\n value: unknown,\n context: IncrementalCacheContext = {}\n): string[] => [\n ...new Set([...(entryTags ?? []), ...(context.tags ?? []), ...(context.softTags ?? []), ...valueTags(value)]),\n];\n\nconst isBuildPhase = (): boolean => process.env.GIGADRIVE_NEXT_BUILD === '1';\n\n/**\n * How long a locally cached entry may serve before the remote copy is re-read.\n * Bounds staleness when another instance rewrites the entry; tag-driven\n * invalidation is unaffected because tag state is checked remotely on every\n * read regardless of where the entry bytes came from.\n */\nconst LOCAL_ENTRY_TTL_MS = 5 * 60_000;\nconst LOCAL_CACHE_MAX_ENTRIES = 256;\nconst LOCAL_CACHE_MAX_TOTAL_BYTES = 64 * 1024 * 1024;\nconst LOCAL_CACHE_MAX_ENTRY_BYTES = 8 * 1024 * 1024;\n\ninterface LocalCacheSlot {\n entry: IncrementalCacheEntry;\n cachedAt: number;\n bytes: number;\n}\n\nconst approximateEntryBytes = (entry: IncrementalCacheEntry): number => {\n try {\n return JSON.stringify(entry)?.length ?? LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n } catch {\n // Circular or otherwise unserializable values are never cached locally.\n return LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n }\n};\n\n/**\n * Byte-bounded in-process LRU in front of the remote entry store.\n *\n * The remote store is an HTTP service backed by object storage, so every miss\n * costs a network round trip — and when that store degrades, page renders\n * degrade with it (a production incident showed second-level blob latency\n * turning every render of a cached page into a multi-second response).\n * Serving entry bytes locally removes that dependency from the hot path while\n * the per-read remote tag-state check keeps `revalidateTag` authoritative.\n */\nclass LocalEntryCache {\n private readonly slots = new Map<string, LocalCacheSlot>();\n private totalBytes = 0;\n\n get(key: string): IncrementalCacheEntry | undefined {\n const slot = this.slots.get(key);\n if (!slot) return undefined;\n if (Date.now() - slot.cachedAt > LOCAL_ENTRY_TTL_MS) {\n this.delete(key);\n return undefined;\n }\n // Refresh recency for LRU eviction.\n this.slots.delete(key);\n this.slots.set(key, slot);\n return slot.entry;\n }\n\n set(key: string, entry: IncrementalCacheEntry): void {\n const bytes = approximateEntryBytes(entry);\n if (bytes > LOCAL_CACHE_MAX_ENTRY_BYTES) {\n this.delete(key);\n return;\n }\n this.delete(key);\n this.slots.set(key, { entry, cachedAt: Date.now(), bytes });\n this.totalBytes += bytes;\n while (this.slots.size > LOCAL_CACHE_MAX_ENTRIES || this.totalBytes > LOCAL_CACHE_MAX_TOTAL_BYTES) {\n const oldest = this.slots.keys().next().value;\n if (oldest === undefined) break;\n this.delete(oldest);\n }\n }\n\n delete(key: string): void {\n const slot = this.slots.get(key);\n if (!slot) return;\n this.slots.delete(key);\n this.totalBytes -= slot.bytes;\n }\n\n clear(): void {\n this.slots.clear();\n this.totalBytes = 0;\n }\n}\n\nconst localEntries = new LocalEntryCache();\n\n/** Test-only: the local entry cache is process-wide, so suites must isolate it. */\nexport const clearLocalEntryCacheForTesting = (): void => localEntries.clear();\n\n/** Shared Network cache handler for ISR, server responses, fetches, and image metadata. */\nexport default class GigadriveNextCacheHandler {\n private readonly buildEntries = new Map<string, IncrementalCacheEntry>();\n /**\n * Next's own on-disk reader, pointed at the build output that ships inside the\n * deployment bundle (`writeStandaloneDirectory` recursively copies\n * `.next/server/{app,pages}`). Injecting a `cacheHandler` replaces Next's\n * FileSystemCache outright, which would otherwise strand every build-time\n * prerender and force a cold re-render of each page on first request.\n * Delegating to Next's reader keeps us off its private on-disk format.\n */\n private buildOutputCache?: Promise<FileSystemCacheLike | undefined>;\n private readonly context: CacheHandlerConstructorContext;\n\n constructor(context: CacheHandlerConstructorContext = {}) {\n this.context = context;\n }\n\n /**\n * Loads Next's on-disk reader lazily, memoized across requests. A Next release\n * that moves or renames the module degrades to \"no build-output fallback\" —\n * the remote cache still serves everything that has been regenerated.\n */\n private loadBuildOutputCache(): Promise<FileSystemCacheLike | undefined> {\n this.buildOutputCache ??= (async () => {\n if (!this.context.fs || !this.context.serverDistDir) return undefined;\n try {\n const module: unknown = await import('next/dist/server/lib/incremental-cache/file-system-cache.js');\n // Next ships this as CommonJS, so the constructor sits behind a different\n // number of `default` hops depending on whether this bundle was loaded as\n // CJS or ESM. Unwrap until a callable turns up rather than guessing.\n let candidate: unknown = module;\n for (let hop = 0; hop < 3 && candidate && typeof candidate !== 'function'; hop += 1) {\n candidate = (candidate as { default?: unknown }).default;\n }\n if (typeof candidate !== 'function') return undefined;\n const FileSystemCache = candidate as new (context: CacheHandlerConstructorContext) => FileSystemCacheLike;\n return new FileSystemCache(this.context);\n } catch {\n return undefined;\n }\n })();\n return this.buildOutputCache;\n }\n\n /**\n * Applies remote tag state to an entry.\n *\n * @returns the entry, a stale-marked copy, or `null` when a tag expired.\n */\n private async applyTagState(entry: IncrementalCacheEntry, tags: string[]): Promise<IncrementalCacheEntry | null> {\n if (tags.length === 0) return entry;\n const tagState = await getRuntimeCacheTagState('incremental', tags);\n if (tagState.expired > entry.lastModified) return null;\n return tagState.stale > entry.lastModified ? { ...entry, lastModified: 1 } : entry;\n }\n\n async get(key: string, context: IncrementalCacheContext = {}): Promise<IncrementalCacheEntry | null> {\n if (isBuildPhase()) {\n const buildEntry = this.buildEntries.get(key) ?? null;\n return isIncrementalCacheEntry(buildEntry) ? buildEntry : null;\n }\n\n const local = localEntries.get(key);\n if (local) {\n return this.applyTagState(local, collectTags(local.tags, local.value, context));\n }\n\n const remote = await readRuntimeCache('incremental', key);\n if (isIncrementalCacheEntry(remote)) {\n localEntries.set(key, remote);\n return this.applyTagState(remote, collectTags(remote.tags, remote.value, context));\n }\n\n // Nothing regenerated yet: fall back to the build-time prerender shipped in\n // the bundle. Tag expiry is still resolved against the remote index — Next's\n // reader only knows its own in-process tag manifest, which is always empty\n // here, so trusting it would resurrect content after a `revalidateTag`.\n const buildOutputCache = await this.loadBuildOutputCache();\n const fromDisk = await buildOutputCache?.get(key, context).catch(() => null);\n if (!isIncrementalCacheEntry(fromDisk)) return null;\n return this.applyTagState(fromDisk, collectTags(fromDisk.tags, fromDisk.value, context));\n }\n\n async set(key: string, data: unknown, context: IncrementalCacheContext): Promise<void> {\n const tags = collectTags(undefined, data, context);\n const entry = { lastModified: Date.now(), value: data, tags, cacheControl: context.cacheControl };\n if (isBuildPhase()) {\n this.buildEntries.set(key, entry);\n return;\n }\n localEntries.set(key, entry);\n try {\n await writeRuntimeCache('incremental', key, entry, tags);\n } catch (error) {\n // The local copy would outlive a failed durable write and mask it from\n // this instance for the whole TTL; drop it so reads retry remotely.\n localEntries.delete(key);\n throw error;\n }\n }\n\n async revalidateTag(tags: string | string[], durations?: { expire?: number }): Promise<void> {\n const normalizedTags = Array.isArray(tags) ? tags : [tags];\n if (isBuildPhase()) {\n for (const [key, entry] of this.buildEntries) {\n if (entry.tags?.some((tag) => normalizedTags.includes(tag))) this.buildEntries.delete(key);\n }\n return;\n }\n await revalidateRuntimeCacheTags('incremental', normalizedTags, durations);\n }\n\n resetRequestCache(): void {}\n}\n","interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n\n // This module is shared by Node and Edge cache-handler bundles. Next.js 16.2\n // rejects a statically analyzable `process.on` call while collecting Edge\n // route data, even though the listener only runs inside the Node runtime.\n // Resolve the optional Node signal API reflectively so Edge builds can load\n // the shared client while Node deployments retain resume rewarming.\n const runtimeProcess = Reflect.get(globalThis, 'process') as NodeJS.Process | undefined;\n const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, 'on');\n if (typeof addSignalListener !== 'function') return;\n\n Reflect.apply(addSignalListener, runtimeProcess, [\n 'SIGUSR2',\n () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n },\n ]);\n};\nregisterResumeRewarm();\n"],"mappings":"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","names":["module"]}
@@ -131,11 +131,17 @@ var getRuntimeCacheTagState = async (kind, tags) => {
131
131
  var registerResumeRewarm = () => {
132
132
  const onGigadrive = process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;
133
133
  if (!onGigadrive) return;
134
- process.on("SIGUSR2", () => {
135
- cachedToken = void 0;
136
- if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
137
- void readRuntimeCache("warmup", "__resume__");
138
- });
134
+ const runtimeProcess = Reflect.get(globalThis, "process");
135
+ const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, "on");
136
+ if (typeof addSignalListener !== "function") return;
137
+ Reflect.apply(addSignalListener, runtimeProcess, [
138
+ "SIGUSR2",
139
+ () => {
140
+ cachedToken = void 0;
141
+ if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;
142
+ void readRuntimeCache("warmup", "__resume__");
143
+ }
144
+ ]);
139
145
  };
140
146
  registerResumeRewarm();
141
147
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-runtime-cache-client.ts","../src/nextjs-cache-handler.ts"],"sourcesContent":["interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n process.on('SIGUSR2', () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n });\n};\nregisterResumeRewarm();\n","import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\n/** Header Next uses to carry an entry's cache tags (comma separated). */\nconst NEXT_CACHE_TAGS_HEADER = 'x-next-cache-tags';\n\ninterface IncrementalCacheContext {\n tags?: string[];\n softTags?: string[];\n cacheControl?: unknown;\n kind?: string;\n}\n\ninterface IncrementalCacheEntry {\n lastModified: number;\n value: unknown | null;\n tags?: string[];\n cacheControl?: unknown;\n}\n\n/** Constructor context Next passes to a custom cache handler. */\ninterface CacheHandlerConstructorContext {\n fs?: unknown;\n serverDistDir?: string;\n dev?: boolean;\n flushToDisk?: boolean;\n revalidatedTags?: string[];\n maxMemoryCacheSize?: number;\n _requestHeaders?: unknown;\n fetchCacheKeyPrefix?: string;\n}\n\ninterface FileSystemCacheLike {\n get(key: string, context: IncrementalCacheContext): Promise<IncrementalCacheEntry | null | undefined>;\n}\n\nconst isIncrementalCacheEntry = (value: unknown): value is IncrementalCacheEntry =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Partial<IncrementalCacheEntry>).lastModified === 'number' &&\n 'value' in value;\n\n/**\n * Reads the cache tags carried by a cached value's own headers.\n *\n * Next never populates `context.tags` for APP_PAGE/APP_ROUTE/PAGES — only fetch\n * cache entries carry tags on the context. For route entries the tags live in\n * the cached value's headers under `x-next-cache-tags` as a comma-joined string,\n * so reading them here is what keeps the remote tag index (and therefore\n * `revalidateTag`) working for pages and route handlers.\n */\nconst valueTags = (value: unknown): string[] => {\n const header = (value as { headers?: Record<string, unknown> } | null)?.headers?.[NEXT_CACHE_TAGS_HEADER];\n if (typeof header !== 'string') return [];\n return header\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean);\n};\n\n/** Every tag relevant to an entry: its own, the request's, and the value's headers. */\nconst collectTags = (\n entryTags: string[] | undefined,\n value: unknown,\n context: IncrementalCacheContext = {}\n): string[] => [\n ...new Set([...(entryTags ?? []), ...(context.tags ?? []), ...(context.softTags ?? []), ...valueTags(value)]),\n];\n\nconst isBuildPhase = (): boolean => process.env.GIGADRIVE_NEXT_BUILD === '1';\n\n/**\n * How long a locally cached entry may serve before the remote copy is re-read.\n * Bounds staleness when another instance rewrites the entry; tag-driven\n * invalidation is unaffected because tag state is checked remotely on every\n * read regardless of where the entry bytes came from.\n */\nconst LOCAL_ENTRY_TTL_MS = 5 * 60_000;\nconst LOCAL_CACHE_MAX_ENTRIES = 256;\nconst LOCAL_CACHE_MAX_TOTAL_BYTES = 64 * 1024 * 1024;\nconst LOCAL_CACHE_MAX_ENTRY_BYTES = 8 * 1024 * 1024;\n\ninterface LocalCacheSlot {\n entry: IncrementalCacheEntry;\n cachedAt: number;\n bytes: number;\n}\n\nconst approximateEntryBytes = (entry: IncrementalCacheEntry): number => {\n try {\n return JSON.stringify(entry)?.length ?? LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n } catch {\n // Circular or otherwise unserializable values are never cached locally.\n return LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n }\n};\n\n/**\n * Byte-bounded in-process LRU in front of the remote entry store.\n *\n * The remote store is an HTTP service backed by object storage, so every miss\n * costs a network round trip — and when that store degrades, page renders\n * degrade with it (a production incident showed second-level blob latency\n * turning every render of a cached page into a multi-second response).\n * Serving entry bytes locally removes that dependency from the hot path while\n * the per-read remote tag-state check keeps `revalidateTag` authoritative.\n */\nclass LocalEntryCache {\n private readonly slots = new Map<string, LocalCacheSlot>();\n private totalBytes = 0;\n\n get(key: string): IncrementalCacheEntry | undefined {\n const slot = this.slots.get(key);\n if (!slot) return undefined;\n if (Date.now() - slot.cachedAt > LOCAL_ENTRY_TTL_MS) {\n this.delete(key);\n return undefined;\n }\n // Refresh recency for LRU eviction.\n this.slots.delete(key);\n this.slots.set(key, slot);\n return slot.entry;\n }\n\n set(key: string, entry: IncrementalCacheEntry): void {\n const bytes = approximateEntryBytes(entry);\n if (bytes > LOCAL_CACHE_MAX_ENTRY_BYTES) {\n this.delete(key);\n return;\n }\n this.delete(key);\n this.slots.set(key, { entry, cachedAt: Date.now(), bytes });\n this.totalBytes += bytes;\n while (this.slots.size > LOCAL_CACHE_MAX_ENTRIES || this.totalBytes > LOCAL_CACHE_MAX_TOTAL_BYTES) {\n const oldest = this.slots.keys().next().value;\n if (oldest === undefined) break;\n this.delete(oldest);\n }\n }\n\n delete(key: string): void {\n const slot = this.slots.get(key);\n if (!slot) return;\n this.slots.delete(key);\n this.totalBytes -= slot.bytes;\n }\n\n clear(): void {\n this.slots.clear();\n this.totalBytes = 0;\n }\n}\n\nconst localEntries = new LocalEntryCache();\n\n/** Test-only: the local entry cache is process-wide, so suites must isolate it. */\nexport const clearLocalEntryCacheForTesting = (): void => localEntries.clear();\n\n/** Shared Network cache handler for ISR, server responses, fetches, and image metadata. */\nexport default class GigadriveNextCacheHandler {\n private readonly buildEntries = new Map<string, IncrementalCacheEntry>();\n /**\n * Next's own on-disk reader, pointed at the build output that ships inside the\n * deployment bundle (`writeStandaloneDirectory` recursively copies\n * `.next/server/{app,pages}`). Injecting a `cacheHandler` replaces Next's\n * FileSystemCache outright, which would otherwise strand every build-time\n * prerender and force a cold re-render of each page on first request.\n * Delegating to Next's reader keeps us off its private on-disk format.\n */\n private buildOutputCache?: Promise<FileSystemCacheLike | undefined>;\n private readonly context: CacheHandlerConstructorContext;\n\n constructor(context: CacheHandlerConstructorContext = {}) {\n this.context = context;\n }\n\n /**\n * Loads Next's on-disk reader lazily, memoized across requests. A Next release\n * that moves or renames the module degrades to \"no build-output fallback\" —\n * the remote cache still serves everything that has been regenerated.\n */\n private loadBuildOutputCache(): Promise<FileSystemCacheLike | undefined> {\n this.buildOutputCache ??= (async () => {\n if (!this.context.fs || !this.context.serverDistDir) return undefined;\n try {\n const module: unknown = await import('next/dist/server/lib/incremental-cache/file-system-cache.js');\n // Next ships this as CommonJS, so the constructor sits behind a different\n // number of `default` hops depending on whether this bundle was loaded as\n // CJS or ESM. Unwrap until a callable turns up rather than guessing.\n let candidate: unknown = module;\n for (let hop = 0; hop < 3 && candidate && typeof candidate !== 'function'; hop += 1) {\n candidate = (candidate as { default?: unknown }).default;\n }\n if (typeof candidate !== 'function') return undefined;\n const FileSystemCache = candidate as new (context: CacheHandlerConstructorContext) => FileSystemCacheLike;\n return new FileSystemCache(this.context);\n } catch {\n return undefined;\n }\n })();\n return this.buildOutputCache;\n }\n\n /**\n * Applies remote tag state to an entry.\n *\n * @returns the entry, a stale-marked copy, or `null` when a tag expired.\n */\n private async applyTagState(entry: IncrementalCacheEntry, tags: string[]): Promise<IncrementalCacheEntry | null> {\n if (tags.length === 0) return entry;\n const tagState = await getRuntimeCacheTagState('incremental', tags);\n if (tagState.expired > entry.lastModified) return null;\n return tagState.stale > entry.lastModified ? { ...entry, lastModified: 1 } : entry;\n }\n\n async get(key: string, context: IncrementalCacheContext = {}): Promise<IncrementalCacheEntry | null> {\n if (isBuildPhase()) {\n const buildEntry = this.buildEntries.get(key) ?? null;\n return isIncrementalCacheEntry(buildEntry) ? buildEntry : null;\n }\n\n const local = localEntries.get(key);\n if (local) {\n return this.applyTagState(local, collectTags(local.tags, local.value, context));\n }\n\n const remote = await readRuntimeCache('incremental', key);\n if (isIncrementalCacheEntry(remote)) {\n localEntries.set(key, remote);\n return this.applyTagState(remote, collectTags(remote.tags, remote.value, context));\n }\n\n // Nothing regenerated yet: fall back to the build-time prerender shipped in\n // the bundle. Tag expiry is still resolved against the remote index — Next's\n // reader only knows its own in-process tag manifest, which is always empty\n // here, so trusting it would resurrect content after a `revalidateTag`.\n const buildOutputCache = await this.loadBuildOutputCache();\n const fromDisk = await buildOutputCache?.get(key, context).catch(() => null);\n if (!isIncrementalCacheEntry(fromDisk)) return null;\n return this.applyTagState(fromDisk, collectTags(fromDisk.tags, fromDisk.value, context));\n }\n\n async set(key: string, data: unknown, context: IncrementalCacheContext): Promise<void> {\n const tags = collectTags(undefined, data, context);\n const entry = { lastModified: Date.now(), value: data, tags, cacheControl: context.cacheControl };\n if (isBuildPhase()) {\n this.buildEntries.set(key, entry);\n return;\n }\n localEntries.set(key, entry);\n try {\n await writeRuntimeCache('incremental', key, entry, tags);\n } catch (error) {\n // The local copy would outlive a failed durable write and mask it from\n // this instance for the whole TTL; drop it so reads retry remotely.\n localEntries.delete(key);\n throw error;\n }\n }\n\n async revalidateTag(tags: string | string[], durations?: { expire?: number }): Promise<void> {\n const normalizedTags = Array.isArray(tags) ? tags : [tags];\n if (isBuildPhase()) {\n for (const [key, entry] of this.buildEntries) {\n if (entry.tags?.some((tag) => normalizedTags.includes(tag))) this.buildEntries.delete(key);\n }\n return;\n }\n await revalidateRuntimeCacheTags('incremental', normalizedTags, durations);\n }\n\n resetRequestCache(): void {}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/nextjs-runtime-cache-client.ts","../src/nextjs-cache-handler.ts"],"sourcesContent":["interface RuntimeCacheEnvelope {\n value: unknown;\n}\n\ninterface AccessTokenResponse {\n access_token: string;\n expires_in?: number;\n}\n\nexport interface RuntimeCacheTagState {\n stale: number;\n expired: number;\n}\n\nlet cachedToken: { value: string; expiresAt: number } | undefined;\n\nconst apiBaseUrl = (): string => (process.env.GIGADRIVE_API_URL ?? 'https://api.gigadrive.network').replace(/\\/$/, '');\n\nconst encodeBinary = (value: unknown, seen = new WeakSet<object>()): unknown => {\n if (value instanceof Uint8Array) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n if (value instanceof ArrayBuffer) {\n return { __gigadriveType: 'bytes', value: Buffer.from(value).toString('base64') };\n }\n // Next stores App Router RSC segment payloads as a `Map<string, Buffer>`\n // (`segmentData`). `Object.entries` on a Map yields nothing, so without an\n // explicit branch the whole map would serialize to `{}` and every prefetched\n // segment would be silently lost on the next read.\n if (value instanceof Map) {\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const entries = [...value.entries()].map(([key, item]) => [encodeBinary(key, seen), encodeBinary(item, seen)]);\n seen.delete(value);\n return { __gigadriveType: 'map', value: entries };\n }\n if (Array.isArray(value)) return value.map((item) => encodeBinary(item, seen));\n if (typeof value !== 'object' || value === null) return value;\n if (seen.has(value)) throw new Error('Next.js cache entry contains a circular value');\n seen.add(value);\n const result: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value)) result[key] = encodeBinary(item, seen);\n seen.delete(value);\n return result;\n};\n\nconst decodeBinary = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(decodeBinary);\n if (typeof value !== 'object' || value === null) return value;\n const record = value as Record<string, unknown>;\n if (record.__gigadriveType === 'bytes' && typeof record.value === 'string')\n return Buffer.from(record.value, 'base64');\n if (record.__gigadriveType === 'map' && Array.isArray(record.value)) {\n return new Map(\n (record.value as unknown[]).map((entry) => {\n const [key, item] = entry as [unknown, unknown];\n return [decodeBinary(key), decodeBinary(item)];\n })\n );\n }\n return Object.fromEntries(Object.entries(record).map(([key, item]) => [key, decodeBinary(item)]));\n};\n\nconst getAccessToken = async (): Promise<string> => {\n if (cachedToken && cachedToken.expiresAt > Date.now() + 30_000) return cachedToken.value;\n const clientId = process.env.GIGADRIVE_CLIENT_ID;\n const clientSecret = process.env.GIGADRIVE_CLIENT_SECRET;\n if (!clientId || !clientSecret) throw new Error('Gigadrive workload credentials are unavailable');\n\n const response = await fetch(`${apiBaseUrl()}/oauth2/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,\n 'content-type': 'application/x-www-form-urlencoded',\n },\n body: 'grant_type=client_credentials',\n });\n if (!response.ok) throw new Error(`Gigadrive workload authentication failed with status ${response.status}`);\n const token = (await response.json()) as AccessTokenResponse;\n if (!token.access_token) throw new Error('Gigadrive workload authentication returned no access token');\n cachedToken = {\n value: token.access_token,\n expiresAt: Date.now() + Math.max(60, token.expires_in ?? 300) * 1000,\n };\n return token.access_token;\n};\n\nconst request = async (pathname: string, init: RequestInit, attempt = 0): Promise<Response> => {\n const token = await getAccessToken();\n try {\n const response = await fetch(`${apiBaseUrl()}${pathname}`, {\n ...init,\n headers: {\n authorization: `Bearer ${token}`,\n 'content-type': 'application/json',\n 'x-gigadrive-deployment-id': process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? '',\n 'x-gigadrive-build-id': process.env.NEXT_BUILD_ID ?? '',\n ...init.headers,\n },\n });\n if (response.status === 401 && attempt === 0) {\n cachedToken = undefined;\n return request(pathname, init, attempt + 1);\n }\n if (response.status >= 500 && attempt < 2) return request(pathname, init, attempt + 1);\n return response;\n } catch (error) {\n if (attempt < 2) return request(pathname, init, attempt + 1);\n throw error;\n }\n};\n\nconst cachePath = (kind: string, key: string): string =>\n `/internal/runtime-cache/v1/entries/${encodeURIComponent(kind)}/${encodeURIComponent(key)}`;\n\nexport const readRuntimeCache = async (kind: string, key: string): Promise<unknown | undefined> => {\n try {\n const response = await request(cachePath(kind, key), { method: 'GET' });\n if (response.status === 404) return undefined;\n if (!response.ok) return undefined;\n const envelope = (await response.json()) as RuntimeCacheEnvelope;\n return decodeBinary(envelope.value);\n } catch {\n return undefined;\n }\n};\n\nexport const writeRuntimeCache = async (\n kind: string,\n key: string,\n value: unknown,\n tags: readonly string[] = []\n): Promise<void> => {\n const response = await request(cachePath(kind, key), {\n method: 'PUT',\n body: JSON.stringify({ value: encodeBinary(value), tags }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache write failed with status ${response.status}`);\n};\n\nexport const revalidateRuntimeCacheTags = async (\n kind: string,\n tags: readonly string[],\n durations?: { expire?: number }\n): Promise<void> => {\n const response = await request('/internal/runtime-cache/v1/tags/revalidate', {\n method: 'POST',\n body: JSON.stringify({ kind, tags, durations }),\n });\n if (!response.ok) throw new Error(`Gigadrive runtime cache revalidation failed with status ${response.status}`);\n};\n\nexport const getRuntimeCacheTagExpiration = async (kind: string, tags: readonly string[]): Promise<number> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/expiration', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return 0;\n const value = (await response.json()) as { expiration?: unknown };\n return typeof value.expiration === 'number' ? value.expiration : 0;\n } catch {\n return 0;\n }\n};\n\nexport const getRuntimeCacheTagState = async (kind: string, tags: readonly string[]): Promise<RuntimeCacheTagState> => {\n try {\n const response = await request('/internal/runtime-cache/v1/tags/state', {\n method: 'POST',\n body: JSON.stringify({ kind, tags }),\n });\n if (!response.ok) return { stale: 0, expired: 0 };\n const value = (await response.json()) as { stale?: unknown; expired?: unknown };\n return {\n stale: typeof value.stale === 'number' ? value.stale : 0,\n expired: typeof value.expired === 'number' ? value.expired : 0,\n };\n } catch {\n return { stale: 0, expired: 0 };\n }\n};\n\nexport const resetRuntimeCacheClientForTests = (): void => {\n cachedToken = undefined;\n};\n\n/**\n * Re-establishes the client's network state after a microVM resume.\n *\n * The guest runtime delivers SIGUSR2 when the instance is restored from a\n * suspend snapshot. At that moment every kept-alive TCP connection from before\n * the freeze is dead, and the cached OAuth token may have expired while the\n * clock was stopped. Dropping the token and dialing one throwaway read\n * re-opens TCP+TLS and refreshes the token concurrently with the guest's own\n * wake-up work, so the first real cache read after a resume does not\n * serialize behind reconnection.\n *\n * Registered only when a Gigadrive deployment marker is present in the\n * environment, so local `next dev`/`next build` never gains a signal listener.\n */\nconst registerResumeRewarm = (): void => {\n const onGigadrive =\n process.env.GIGADRIVE_DEPLOYMENT_ID ?? process.env.NEBULA_DEPLOYMENT_ID ?? process.env.GIGADRIVE_CLIENT_ID;\n if (!onGigadrive) return;\n\n // This module is shared by Node and Edge cache-handler bundles. Next.js 16.2\n // rejects a statically analyzable `process.on` call while collecting Edge\n // route data, even though the listener only runs inside the Node runtime.\n // Resolve the optional Node signal API reflectively so Edge builds can load\n // the shared client while Node deployments retain resume rewarming.\n const runtimeProcess = Reflect.get(globalThis, 'process') as NodeJS.Process | undefined;\n const addSignalListener = runtimeProcess && Reflect.get(runtimeProcess, 'on');\n if (typeof addSignalListener !== 'function') return;\n\n Reflect.apply(addSignalListener, runtimeProcess, [\n 'SIGUSR2',\n () => {\n cachedToken = undefined;\n if (!process.env.GIGADRIVE_CLIENT_ID || !process.env.GIGADRIVE_CLIENT_SECRET) return;\n void readRuntimeCache('warmup', '__resume__');\n },\n ]);\n};\nregisterResumeRewarm();\n","import {\n getRuntimeCacheTagState,\n readRuntimeCache,\n revalidateRuntimeCacheTags,\n writeRuntimeCache,\n} from './nextjs-runtime-cache-client';\n\n/** Header Next uses to carry an entry's cache tags (comma separated). */\nconst NEXT_CACHE_TAGS_HEADER = 'x-next-cache-tags';\n\ninterface IncrementalCacheContext {\n tags?: string[];\n softTags?: string[];\n cacheControl?: unknown;\n kind?: string;\n}\n\ninterface IncrementalCacheEntry {\n lastModified: number;\n value: unknown | null;\n tags?: string[];\n cacheControl?: unknown;\n}\n\n/** Constructor context Next passes to a custom cache handler. */\ninterface CacheHandlerConstructorContext {\n fs?: unknown;\n serverDistDir?: string;\n dev?: boolean;\n flushToDisk?: boolean;\n revalidatedTags?: string[];\n maxMemoryCacheSize?: number;\n _requestHeaders?: unknown;\n fetchCacheKeyPrefix?: string;\n}\n\ninterface FileSystemCacheLike {\n get(key: string, context: IncrementalCacheContext): Promise<IncrementalCacheEntry | null | undefined>;\n}\n\nconst isIncrementalCacheEntry = (value: unknown): value is IncrementalCacheEntry =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Partial<IncrementalCacheEntry>).lastModified === 'number' &&\n 'value' in value;\n\n/**\n * Reads the cache tags carried by a cached value's own headers.\n *\n * Next never populates `context.tags` for APP_PAGE/APP_ROUTE/PAGES — only fetch\n * cache entries carry tags on the context. For route entries the tags live in\n * the cached value's headers under `x-next-cache-tags` as a comma-joined string,\n * so reading them here is what keeps the remote tag index (and therefore\n * `revalidateTag`) working for pages and route handlers.\n */\nconst valueTags = (value: unknown): string[] => {\n const header = (value as { headers?: Record<string, unknown> } | null)?.headers?.[NEXT_CACHE_TAGS_HEADER];\n if (typeof header !== 'string') return [];\n return header\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean);\n};\n\n/** Every tag relevant to an entry: its own, the request's, and the value's headers. */\nconst collectTags = (\n entryTags: string[] | undefined,\n value: unknown,\n context: IncrementalCacheContext = {}\n): string[] => [\n ...new Set([...(entryTags ?? []), ...(context.tags ?? []), ...(context.softTags ?? []), ...valueTags(value)]),\n];\n\nconst isBuildPhase = (): boolean => process.env.GIGADRIVE_NEXT_BUILD === '1';\n\n/**\n * How long a locally cached entry may serve before the remote copy is re-read.\n * Bounds staleness when another instance rewrites the entry; tag-driven\n * invalidation is unaffected because tag state is checked remotely on every\n * read regardless of where the entry bytes came from.\n */\nconst LOCAL_ENTRY_TTL_MS = 5 * 60_000;\nconst LOCAL_CACHE_MAX_ENTRIES = 256;\nconst LOCAL_CACHE_MAX_TOTAL_BYTES = 64 * 1024 * 1024;\nconst LOCAL_CACHE_MAX_ENTRY_BYTES = 8 * 1024 * 1024;\n\ninterface LocalCacheSlot {\n entry: IncrementalCacheEntry;\n cachedAt: number;\n bytes: number;\n}\n\nconst approximateEntryBytes = (entry: IncrementalCacheEntry): number => {\n try {\n return JSON.stringify(entry)?.length ?? LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n } catch {\n // Circular or otherwise unserializable values are never cached locally.\n return LOCAL_CACHE_MAX_ENTRY_BYTES + 1;\n }\n};\n\n/**\n * Byte-bounded in-process LRU in front of the remote entry store.\n *\n * The remote store is an HTTP service backed by object storage, so every miss\n * costs a network round trip — and when that store degrades, page renders\n * degrade with it (a production incident showed second-level blob latency\n * turning every render of a cached page into a multi-second response).\n * Serving entry bytes locally removes that dependency from the hot path while\n * the per-read remote tag-state check keeps `revalidateTag` authoritative.\n */\nclass LocalEntryCache {\n private readonly slots = new Map<string, LocalCacheSlot>();\n private totalBytes = 0;\n\n get(key: string): IncrementalCacheEntry | undefined {\n const slot = this.slots.get(key);\n if (!slot) return undefined;\n if (Date.now() - slot.cachedAt > LOCAL_ENTRY_TTL_MS) {\n this.delete(key);\n return undefined;\n }\n // Refresh recency for LRU eviction.\n this.slots.delete(key);\n this.slots.set(key, slot);\n return slot.entry;\n }\n\n set(key: string, entry: IncrementalCacheEntry): void {\n const bytes = approximateEntryBytes(entry);\n if (bytes > LOCAL_CACHE_MAX_ENTRY_BYTES) {\n this.delete(key);\n return;\n }\n this.delete(key);\n this.slots.set(key, { entry, cachedAt: Date.now(), bytes });\n this.totalBytes += bytes;\n while (this.slots.size > LOCAL_CACHE_MAX_ENTRIES || this.totalBytes > LOCAL_CACHE_MAX_TOTAL_BYTES) {\n const oldest = this.slots.keys().next().value;\n if (oldest === undefined) break;\n this.delete(oldest);\n }\n }\n\n delete(key: string): void {\n const slot = this.slots.get(key);\n if (!slot) return;\n this.slots.delete(key);\n this.totalBytes -= slot.bytes;\n }\n\n clear(): void {\n this.slots.clear();\n this.totalBytes = 0;\n }\n}\n\nconst localEntries = new LocalEntryCache();\n\n/** Test-only: the local entry cache is process-wide, so suites must isolate it. */\nexport const clearLocalEntryCacheForTesting = (): void => localEntries.clear();\n\n/** Shared Network cache handler for ISR, server responses, fetches, and image metadata. */\nexport default class GigadriveNextCacheHandler {\n private readonly buildEntries = new Map<string, IncrementalCacheEntry>();\n /**\n * Next's own on-disk reader, pointed at the build output that ships inside the\n * deployment bundle (`writeStandaloneDirectory` recursively copies\n * `.next/server/{app,pages}`). Injecting a `cacheHandler` replaces Next's\n * FileSystemCache outright, which would otherwise strand every build-time\n * prerender and force a cold re-render of each page on first request.\n * Delegating to Next's reader keeps us off its private on-disk format.\n */\n private buildOutputCache?: Promise<FileSystemCacheLike | undefined>;\n private readonly context: CacheHandlerConstructorContext;\n\n constructor(context: CacheHandlerConstructorContext = {}) {\n this.context = context;\n }\n\n /**\n * Loads Next's on-disk reader lazily, memoized across requests. A Next release\n * that moves or renames the module degrades to \"no build-output fallback\" —\n * the remote cache still serves everything that has been regenerated.\n */\n private loadBuildOutputCache(): Promise<FileSystemCacheLike | undefined> {\n this.buildOutputCache ??= (async () => {\n if (!this.context.fs || !this.context.serverDistDir) return undefined;\n try {\n const module: unknown = await import('next/dist/server/lib/incremental-cache/file-system-cache.js');\n // Next ships this as CommonJS, so the constructor sits behind a different\n // number of `default` hops depending on whether this bundle was loaded as\n // CJS or ESM. Unwrap until a callable turns up rather than guessing.\n let candidate: unknown = module;\n for (let hop = 0; hop < 3 && candidate && typeof candidate !== 'function'; hop += 1) {\n candidate = (candidate as { default?: unknown }).default;\n }\n if (typeof candidate !== 'function') return undefined;\n const FileSystemCache = candidate as new (context: CacheHandlerConstructorContext) => FileSystemCacheLike;\n return new FileSystemCache(this.context);\n } catch {\n return undefined;\n }\n })();\n return this.buildOutputCache;\n }\n\n /**\n * Applies remote tag state to an entry.\n *\n * @returns the entry, a stale-marked copy, or `null` when a tag expired.\n */\n private async applyTagState(entry: IncrementalCacheEntry, tags: string[]): Promise<IncrementalCacheEntry | null> {\n if (tags.length === 0) return entry;\n const tagState = await getRuntimeCacheTagState('incremental', tags);\n if (tagState.expired > entry.lastModified) return null;\n return tagState.stale > entry.lastModified ? { ...entry, lastModified: 1 } : entry;\n }\n\n async get(key: string, context: IncrementalCacheContext = {}): Promise<IncrementalCacheEntry | null> {\n if (isBuildPhase()) {\n const buildEntry = this.buildEntries.get(key) ?? null;\n return isIncrementalCacheEntry(buildEntry) ? buildEntry : null;\n }\n\n const local = localEntries.get(key);\n if (local) {\n return this.applyTagState(local, collectTags(local.tags, local.value, context));\n }\n\n const remote = await readRuntimeCache('incremental', key);\n if (isIncrementalCacheEntry(remote)) {\n localEntries.set(key, remote);\n return this.applyTagState(remote, collectTags(remote.tags, remote.value, context));\n }\n\n // Nothing regenerated yet: fall back to the build-time prerender shipped in\n // the bundle. Tag expiry is still resolved against the remote index — Next's\n // reader only knows its own in-process tag manifest, which is always empty\n // here, so trusting it would resurrect content after a `revalidateTag`.\n const buildOutputCache = await this.loadBuildOutputCache();\n const fromDisk = await buildOutputCache?.get(key, context).catch(() => null);\n if (!isIncrementalCacheEntry(fromDisk)) return null;\n return this.applyTagState(fromDisk, collectTags(fromDisk.tags, fromDisk.value, context));\n }\n\n async set(key: string, data: unknown, context: IncrementalCacheContext): Promise<void> {\n const tags = collectTags(undefined, data, context);\n const entry = { lastModified: Date.now(), value: data, tags, cacheControl: context.cacheControl };\n if (isBuildPhase()) {\n this.buildEntries.set(key, entry);\n return;\n }\n localEntries.set(key, entry);\n try {\n await writeRuntimeCache('incremental', key, entry, tags);\n } catch (error) {\n // The local copy would outlive a failed durable write and mask it from\n // this instance for the whole TTL; drop it so reads retry remotely.\n localEntries.delete(key);\n throw error;\n }\n }\n\n async revalidateTag(tags: string | string[], durations?: { expire?: number }): Promise<void> {\n const normalizedTags = Array.isArray(tags) ? tags : [tags];\n if (isBuildPhase()) {\n for (const [key, entry] of this.buildEntries) {\n if (entry.tags?.some((tag) => normalizedTags.includes(tag))) this.buildEntries.delete(key);\n }\n return;\n }\n await revalidateRuntimeCacheTags('incremental', normalizedTags, durations);\n }\n\n resetRequestCache(): void {}\n}\n"],"mappings":";AAcA,IAAI;AAEJ,IAAM,aAAa,OAAe,QAAQ,IAAI,qBAAqB,iCAAiC,QAAQ,OAAO,EAAE;AAErH,IAAM,eAAe,CAAC,OAAgB,OAAO,oBAAI,QAAgB,MAAe;AAC9E,MAAI,iBAAiB,YAAY;AAC/B,WAAO,EAAE,iBAAiB,SAAS,OAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,EAAE;AAAA,EAClF;AACA,MAAI,iBAAiB,aAAa;AAChC,WAAO,EAAE,iBAAiB,SAAS,OAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,EAAE;AAAA,EAClF;AAKA,MAAI,iBAAiB,KAAK;AACxB,QAAI,KAAK,IAAI,KAAK,EAAG,OAAM,IAAI,MAAM,+CAA+C;AACpF,SAAK,IAAI,KAAK;AACd,UAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,GAAG,aAAa,MAAM,IAAI,CAAC,CAAC;AAC7G,SAAK,OAAO,KAAK;AACjB,WAAO,EAAE,iBAAiB,OAAO,OAAO,QAAQ;AAAA,EAClD;AACA,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,CAAC,SAAS,aAAa,MAAM,IAAI,CAAC;AAC7E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,MAAI,KAAK,IAAI,KAAK,EAAG,OAAM,IAAI,MAAM,+CAA+C;AACpF,OAAK,IAAI,KAAK;AACd,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,EAAG,QAAO,GAAG,IAAI,aAAa,MAAM,IAAI;AACtF,OAAK,OAAO,KAAK;AACjB,SAAO;AACT;AAEA,IAAM,eAAe,CAAC,UAA4B;AAChD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,YAAY;AACvD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,SAAS;AACf,MAAI,OAAO,oBAAoB,WAAW,OAAO,OAAO,UAAU;AAChE,WAAO,OAAO,KAAK,OAAO,OAAO,QAAQ;AAC3C,MAAI,OAAO,oBAAoB,SAAS,MAAM,QAAQ,OAAO,KAAK,GAAG;AACnE,WAAO,IAAI;AAAA,MACR,OAAO,MAAoB,IAAI,CAAC,UAAU;AACzC,cAAM,CAAC,KAAK,IAAI,IAAI;AACpB,eAAO,CAAC,aAAa,GAAG,GAAG,aAAa,IAAI,CAAC;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,OAAO,YAAY,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,aAAa,IAAI,CAAC,CAAC,CAAC;AAClG;AAEA,IAAM,iBAAiB,YAA6B;AAClD,MAAI,eAAe,YAAY,YAAY,KAAK,IAAI,IAAI,IAAQ,QAAO,YAAY;AACnF,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,eAAe,QAAQ,IAAI;AACjC,MAAI,CAAC,YAAY,CAAC,aAAc,OAAM,IAAI,MAAM,gDAAgD;AAEhG,QAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,iBAAiB;AAAA,IAC3D,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,eAAe,SAAS,OAAO,KAAK,GAAG,QAAQ,IAAI,YAAY,EAAE,EAAE,SAAS,QAAQ,CAAC;AAAA,MACrF,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,wDAAwD,SAAS,MAAM,EAAE;AAC3G,QAAM,QAAS,MAAM,SAAS,KAAK;AACnC,MAAI,CAAC,MAAM,aAAc,OAAM,IAAI,MAAM,4DAA4D;AACrG,gBAAc;AAAA,IACZ,OAAO,MAAM;AAAA,IACb,WAAW,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,cAAc,GAAG,IAAI;AAAA,EAClE;AACA,SAAO,MAAM;AACf;AAEA,IAAM,UAAU,OAAO,UAAkB,MAAmB,UAAU,MAAyB;AAC7F,QAAM,QAAQ,MAAM,eAAe;AACnC,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,QAAQ,IAAI;AAAA,MACzD,GAAG;AAAA,MACH,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,QAC9B,gBAAgB;AAAA,QAChB,6BAA6B,QAAQ,IAAI,2BAA2B,QAAQ,IAAI,wBAAwB;AAAA,QACxG,wBAAwB,QAAQ,IAAI,iBAAiB;AAAA,QACrD,GAAG,KAAK;AAAA,MACV;AAAA,IACF,CAAC;AACD,QAAI,SAAS,WAAW,OAAO,YAAY,GAAG;AAC5C,oBAAc;AACd,aAAO,QAAQ,UAAU,MAAM,UAAU,CAAC;AAAA,IAC5C;AACA,QAAI,SAAS,UAAU,OAAO,UAAU,EAAG,QAAO,QAAQ,UAAU,MAAM,UAAU,CAAC;AACrF,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,UAAU,EAAG,QAAO,QAAQ,UAAU,MAAM,UAAU,CAAC;AAC3D,UAAM;AAAA,EACR;AACF;AAEA,IAAM,YAAY,CAAC,MAAc,QAC/B,sCAAsC,mBAAmB,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC;AAEpF,IAAM,mBAAmB,OAAO,MAAc,QAA8C;AACjG,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,UAAU,MAAM,GAAG,GAAG,EAAE,QAAQ,MAAM,CAAC;AACtE,QAAI,SAAS,WAAW,IAAK,QAAO;AACpC,QAAI,CAAC,SAAS,GAAI,QAAO;AACzB,UAAM,WAAY,MAAM,SAAS,KAAK;AACtC,WAAO,aAAa,SAAS,KAAK;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,oBAAoB,OAC/B,MACA,KACA,OACA,OAA0B,CAAC,MACT;AAClB,QAAM,WAAW,MAAM,QAAQ,UAAU,MAAM,GAAG,GAAG;AAAA,IACnD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,OAAO,aAAa,KAAK,GAAG,KAAK,CAAC;AAAA,EAC3D,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,oDAAoD,SAAS,MAAM,EAAE;AACzG;AAEO,IAAM,6BAA6B,OACxC,MACA,MACA,cACkB;AAClB,QAAM,WAAW,MAAM,QAAQ,8CAA8C;AAAA,IAC3E,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,EAAE,MAAM,MAAM,UAAU,CAAC;AAAA,EAChD,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,2DAA2D,SAAS,MAAM,EAAE;AAChH;AAgBO,IAAM,0BAA0B,OAAO,MAAc,SAA2D;AACrH,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,yCAAyC;AAAA,MACtE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAAA,IACrC,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,QAAO,EAAE,OAAO,GAAG,SAAS,EAAE;AAChD,UAAM,QAAS,MAAM,SAAS,KAAK;AACnC,WAAO;AAAA,MACL,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,MACvD,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAAA,IAC/D;AAAA,EACF,QAAQ;AACN,WAAO,EAAE,OAAO,GAAG,SAAS,EAAE;AAAA,EAChC;AACF;AAoBA,IAAM,uBAAuB,MAAY;AACvC,QAAM,cACJ,QAAQ,IAAI,2BAA2B,QAAQ,IAAI,wBAAwB,QAAQ,IAAI;AACzF,MAAI,CAAC,YAAa;AAOlB,QAAM,iBAAiB,QAAQ,IAAI,YAAY,SAAS;AACxD,QAAM,oBAAoB,kBAAkB,QAAQ,IAAI,gBAAgB,IAAI;AAC5E,MAAI,OAAO,sBAAsB,WAAY;AAE7C,UAAQ,MAAM,mBAAmB,gBAAgB;AAAA,IAC/C;AAAA,IACA,MAAM;AACJ,oBAAc;AACd,UAAI,CAAC,QAAQ,IAAI,uBAAuB,CAAC,QAAQ,IAAI,wBAAyB;AAC9E,WAAK,iBAAiB,UAAU,YAAY;AAAA,IAC9C;AAAA,EACF,CAAC;AACH;AACA,qBAAqB;;;ACxNrB,IAAM,yBAAyB;AAgC/B,IAAM,0BAA0B,CAAC,UAC/B,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAAyC,iBAAiB,YAClE,WAAW;AAWb,IAAM,YAAY,CAAC,UAA6B;AAC9C,QAAM,SAAU,OAAwD,UAAU,sBAAsB;AACxG,MAAI,OAAO,WAAW,SAAU,QAAO,CAAC;AACxC,SAAO,OACJ,MAAM,GAAG,EACT,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EACvB,OAAO,OAAO;AACnB;AAGA,IAAM,cAAc,CAClB,WACA,OACA,UAAmC,CAAC,MACvB;AAAA,EACb,GAAG,oBAAI,IAAI,CAAC,GAAI,aAAa,CAAC,GAAI,GAAI,QAAQ,QAAQ,CAAC,GAAI,GAAI,QAAQ,YAAY,CAAC,GAAI,GAAG,UAAU,KAAK,CAAC,CAAC;AAC9G;AAEA,IAAM,eAAe,MAAe,QAAQ,IAAI,yBAAyB;AAQzE,IAAM,qBAAqB,IAAI;AAC/B,IAAM,0BAA0B;AAChC,IAAM,8BAA8B,KAAK,OAAO;AAChD,IAAM,8BAA8B,IAAI,OAAO;AAQ/C,IAAM,wBAAwB,CAAC,UAAyC;AACtE,MAAI;AACF,WAAO,KAAK,UAAU,KAAK,GAAG,UAAU,8BAA8B;AAAA,EACxE,QAAQ;AAEN,WAAO,8BAA8B;AAAA,EACvC;AACF;AAYA,IAAM,kBAAN,MAAsB;AAAA,EACH,QAAQ,oBAAI,IAA4B;AAAA,EACjD,aAAa;AAAA,EAErB,IAAI,KAAgD;AAClD,UAAM,OAAO,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,KAAK,IAAI,IAAI,KAAK,WAAW,oBAAoB;AACnD,WAAK,OAAO,GAAG;AACf,aAAO;AAAA,IACT;AAEA,SAAK,MAAM,OAAO,GAAG;AACrB,SAAK,MAAM,IAAI,KAAK,IAAI;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,KAAa,OAAoC;AACnD,UAAM,QAAQ,sBAAsB,KAAK;AACzC,QAAI,QAAQ,6BAA6B;AACvC,WAAK,OAAO,GAAG;AACf;AAAA,IACF;AACA,SAAK,OAAO,GAAG;AACf,SAAK,MAAM,IAAI,KAAK,EAAE,OAAO,UAAU,KAAK,IAAI,GAAG,MAAM,CAAC;AAC1D,SAAK,cAAc;AACnB,WAAO,KAAK,MAAM,OAAO,2BAA2B,KAAK,aAAa,6BAA6B;AACjG,YAAM,SAAS,KAAK,MAAM,KAAK,EAAE,KAAK,EAAE;AACxC,UAAI,WAAW,OAAW;AAC1B,WAAK,OAAO,MAAM;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,OAAO,KAAmB;AACxB,UAAM,OAAO,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,KAAM;AACX,SAAK,MAAM,OAAO,GAAG;AACrB,SAAK,cAAc,KAAK;AAAA,EAC1B;AAAA,EAEA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,aAAa;AAAA,EACpB;AACF;AAEA,IAAM,eAAe,IAAI,gBAAgB;AAGlC,IAAM,iCAAiC,MAAY,aAAa,MAAM;AAG7E,IAAqB,4BAArB,MAA+C;AAAA,EAC5B,eAAe,oBAAI,IAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS/D;AAAA,EACS;AAAA,EAEjB,YAAY,UAA0C,CAAC,GAAG;AACxD,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,uBAAiE;AACvE,SAAK,sBAAsB,YAAY;AACrC,UAAI,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,QAAQ,cAAe,QAAO;AAC5D,UAAI;AACF,cAAM,SAAkB,MAAM,OAAO,6DAA6D;AAIlG,YAAI,YAAqB;AACzB,iBAAS,MAAM,GAAG,MAAM,KAAK,aAAa,OAAO,cAAc,YAAY,OAAO,GAAG;AACnF,sBAAa,UAAoC;AAAA,QACnD;AACA,YAAI,OAAO,cAAc,WAAY,QAAO;AAC5C,cAAM,kBAAkB;AACxB,eAAO,IAAI,gBAAgB,KAAK,OAAO;AAAA,MACzC,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG;AACH,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,cAAc,OAA8B,MAAuD;AAC/G,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,UAAM,WAAW,MAAM,wBAAwB,eAAe,IAAI;AAClE,QAAI,SAAS,UAAU,MAAM,aAAc,QAAO;AAClD,WAAO,SAAS,QAAQ,MAAM,eAAe,EAAE,GAAG,OAAO,cAAc,EAAE,IAAI;AAAA,EAC/E;AAAA,EAEA,MAAM,IAAI,KAAa,UAAmC,CAAC,GAA0C;AACnG,QAAI,aAAa,GAAG;AAClB,YAAM,aAAa,KAAK,aAAa,IAAI,GAAG,KAAK;AACjD,aAAO,wBAAwB,UAAU,IAAI,aAAa;AAAA,IAC5D;AAEA,UAAM,QAAQ,aAAa,IAAI,GAAG;AAClC,QAAI,OAAO;AACT,aAAO,KAAK,cAAc,OAAO,YAAY,MAAM,MAAM,MAAM,OAAO,OAAO,CAAC;AAAA,IAChF;AAEA,UAAM,SAAS,MAAM,iBAAiB,eAAe,GAAG;AACxD,QAAI,wBAAwB,MAAM,GAAG;AACnC,mBAAa,IAAI,KAAK,MAAM;AAC5B,aAAO,KAAK,cAAc,QAAQ,YAAY,OAAO,MAAM,OAAO,OAAO,OAAO,CAAC;AAAA,IACnF;AAMA,UAAM,mBAAmB,MAAM,KAAK,qBAAqB;AACzD,UAAM,WAAW,MAAM,kBAAkB,IAAI,KAAK,OAAO,EAAE,MAAM,MAAM,IAAI;AAC3E,QAAI,CAAC,wBAAwB,QAAQ,EAAG,QAAO;AAC/C,WAAO,KAAK,cAAc,UAAU,YAAY,SAAS,MAAM,SAAS,OAAO,OAAO,CAAC;AAAA,EACzF;AAAA,EAEA,MAAM,IAAI,KAAa,MAAe,SAAiD;AACrF,UAAM,OAAO,YAAY,QAAW,MAAM,OAAO;AACjD,UAAM,QAAQ,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,MAAM,MAAM,cAAc,QAAQ,aAAa;AAChG,QAAI,aAAa,GAAG;AAClB,WAAK,aAAa,IAAI,KAAK,KAAK;AAChC;AAAA,IACF;AACA,iBAAa,IAAI,KAAK,KAAK;AAC3B,QAAI;AACF,YAAM,kBAAkB,eAAe,KAAK,OAAO,IAAI;AAAA,IACzD,SAAS,OAAO;AAGd,mBAAa,OAAO,GAAG;AACvB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,MAAyB,WAAgD;AAC3F,UAAM,iBAAiB,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AACzD,QAAI,aAAa,GAAG;AAClB,iBAAW,CAAC,KAAK,KAAK,KAAK,KAAK,cAAc;AAC5C,YAAI,MAAM,MAAM,KAAK,CAAC,QAAQ,eAAe,SAAS,GAAG,CAAC,EAAG,MAAK,aAAa,OAAO,GAAG;AAAA,MAC3F;AACA;AAAA,IACF;AACA,UAAM,2BAA2B,eAAe,gBAAgB,SAAS;AAAA,EAC3E;AAAA,EAEA,oBAA0B;AAAA,EAAC;AAC7B;","names":[]}
@@ -23,11 +23,12 @@ __export(nextjs_image_loader_exports, {
23
23
  default: () => gigadriveNextImageLoader
24
24
  });
25
25
  module.exports = __toCommonJS(nextjs_image_loader_exports);
26
+ var sourcePathname = (source) => source.startsWith("http://") || source.startsWith("https://") ? new URL(source).pathname : source.split(/[?#]/, 1)[0];
26
27
  var filenameHint = (source) => {
27
- const pathname = source.startsWith("http://") || source.startsWith("https://") ? new URL(source).pathname : source;
28
- const candidate = pathname.split("/").filter(Boolean).at(-1)?.split("?")[0] ?? "image";
28
+ const candidate = sourcePathname(source).split("/").filter(Boolean).at(-1) ?? "image";
29
29
  return /\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate) ? candidate : `${candidate || "image"}.png`;
30
30
  };
31
+ var isSvgSource = (source) => /\.svg$/i.test(sourcePathname(source));
31
32
  var MAXIMUM_OPTIMIZER_URL_LENGTH = 2e3;
32
33
  var stripDeploymentMarker = (src) => {
33
34
  if (!src.startsWith("/") || !src.includes("?")) return src;
@@ -38,6 +39,7 @@ var stripDeploymentMarker = (src) => {
38
39
  return remaining ? `${pathname}?${remaining}` : pathname;
39
40
  };
40
41
  function gigadriveNextImageLoader({ src, width, quality }) {
42
+ if (isSvgSource(src)) return src;
41
43
  const stableSrc = stripDeploymentMarker(src);
42
44
  const parameters = new URLSearchParams({ width: String(width) });
43
45
  if (quality !== void 0) parameters.set("quality", String(quality));
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-image-loader.ts"],"sourcesContent":["interface NextImageLoaderOptions {\n src: string;\n width: number;\n quality?: number;\n}\n\nconst filenameHint = (source: string): string => {\n const pathname = source.startsWith('http://') || source.startsWith('https://') ? new URL(source).pathname : source;\n const candidate = pathname.split('/').filter(Boolean).at(-1)?.split('?')[0] ?? 'image';\n return /\\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate)\n ? candidate\n : `${candidate || 'image'}.png`;\n};\n\n// Conservative bound below common CDN/proxy URL limits (~4-8 KB). The encoded\n// source is embedded in the optimizer path, so an oversized source URL cannot\n// be shortened losslessly — such images are served unoptimized instead.\nconst MAXIMUM_OPTIMIZER_URL_LENGTH = 2000;\n\n/**\n * Removes Next's `dpl` deployment marker from a local source.\n *\n * Next appends `?dpl=<deploymentId>` to local asset sources whenever a\n * deployment id is configured. The Gigadrive optimizer resolves the deployment\n * from the request hostname and never reads `dpl`, so keeping it only changes\n * the optimizer URL on every deploy — invalidating the CDN's image cache for\n * files whose content-hashed names already guarantee freshness, and forcing a\n * full re-optimization burst after each release.\n */\nconst stripDeploymentMarker = (src: string): string => {\n if (!src.startsWith('/') || !src.includes('?')) return src;\n const [pathname, query] = src.split('?', 2);\n const parameters = new URLSearchParams(query);\n parameters.delete('dpl');\n const remaining = parameters.toString();\n return remaining ? `${pathname}?${remaining}` : pathname;\n};\n\n/** Builds the stable app-host URL consumed by Gigadrive's managed image optimizer. */\nexport default function gigadriveNextImageLoader({ src, width, quality }: NextImageLoaderOptions): string {\n const stableSrc = stripDeploymentMarker(src);\n const parameters = new URLSearchParams({ width: String(width) });\n if (quality !== undefined) parameters.set('quality', String(quality));\n const optimizerUrl = `/_gigadrive/image/${encodeURIComponent(stableSrc)}/${encodeURIComponent(filenameHint(stableSrc))}?${parameters}`;\n return optimizerUrl.length > MAXIMUM_OPTIMIZER_URL_LENGTH ? src : optimizerUrl;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,IAAM,eAAe,CAAC,WAA2B;AAC/C,QAAM,WAAW,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU,IAAI,IAAI,IAAI,MAAM,EAAE,WAAW;AAC5G,QAAM,YAAY,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AAC/E,SAAO,gEAAgE,KAAK,SAAS,IACjF,YACA,GAAG,aAAa,OAAO;AAC7B;AAKA,IAAM,+BAA+B;AAYrC,IAAM,wBAAwB,CAAC,QAAwB;AACrD,MAAI,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,EAAG,QAAO;AACvD,QAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,KAAK,CAAC;AAC1C,QAAM,aAAa,IAAI,gBAAgB,KAAK;AAC5C,aAAW,OAAO,KAAK;AACvB,QAAM,YAAY,WAAW,SAAS;AACtC,SAAO,YAAY,GAAG,QAAQ,IAAI,SAAS,KAAK;AAClD;AAGe,SAAR,yBAA0C,EAAE,KAAK,OAAO,QAAQ,GAAmC;AACxG,QAAM,YAAY,sBAAsB,GAAG;AAC3C,QAAM,aAAa,IAAI,gBAAgB,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;AAC/D,MAAI,YAAY,OAAW,YAAW,IAAI,WAAW,OAAO,OAAO,CAAC;AACpE,QAAM,eAAe,qBAAqB,mBAAmB,SAAS,CAAC,IAAI,mBAAmB,aAAa,SAAS,CAAC,CAAC,IAAI,UAAU;AACpI,SAAO,aAAa,SAAS,+BAA+B,MAAM;AACpE;","names":[]}
1
+ {"version":3,"sources":["../src/nextjs-image-loader.ts"],"sourcesContent":["interface NextImageLoaderOptions {\n src: string;\n width: number;\n quality?: number;\n}\n\n/** The path portion of a source, with any query string or fragment removed. */\nconst sourcePathname = (source: string): string =>\n source.startsWith('http://') || source.startsWith('https://') ? new URL(source).pathname : source.split(/[?#]/, 1)[0];\n\nconst filenameHint = (source: string): string => {\n const candidate = sourcePathname(source).split('/').filter(Boolean).at(-1) ?? 'image';\n return /\\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate)\n ? candidate\n : `${candidate || 'image'}.png`;\n};\n\nconst isSvgSource = (source: string): boolean => /\\.svg$/i.test(sourcePathname(source));\n\n// Conservative bound below common CDN/proxy URL limits (~4-8 KB). The encoded\n// source is embedded in the optimizer path, so an oversized source URL cannot\n// be shortened losslessly — such images are served unoptimized instead.\nconst MAXIMUM_OPTIMIZER_URL_LENGTH = 2000;\n\n/**\n * Removes Next's `dpl` deployment marker from a local source.\n *\n * Next appends `?dpl=<deploymentId>` to local asset sources whenever a\n * deployment id is configured. The Gigadrive optimizer resolves the deployment\n * from the request hostname and never reads `dpl`, so keeping it only changes\n * the optimizer URL on every deploy — invalidating the CDN's image cache for\n * files whose content-hashed names already guarantee freshness, and forcing a\n * full re-optimization burst after each release.\n */\nconst stripDeploymentMarker = (src: string): string => {\n if (!src.startsWith('/') || !src.includes('?')) return src;\n const [pathname, query] = src.split('?', 2);\n const parameters = new URLSearchParams(query);\n parameters.delete('dpl');\n const remaining = parameters.toString();\n return remaining ? `${pathname}?${remaining}` : pathname;\n};\n\n/** Builds the stable app-host URL consumed by Gigadrive's managed image optimizer. */\nexport default function gigadriveNextImageLoader({ src, width, quality }: NextImageLoaderOptions): string {\n // No optimizer backend can rasterize SVG, so routing one through the optimizer\n // is always a pass-through: a wasted redirect and an extra request for bytes\n // the origin already serves. Next's own get-img-props marks `.svg` unoptimized\n // before any loader runs, but that bypass is skipped once a custom loaderFile\n // is configured — which is exactly what this adapter injects.\n if (isSvgSource(src)) return src;\n\n const stableSrc = stripDeploymentMarker(src);\n const parameters = new URLSearchParams({ width: String(width) });\n if (quality !== undefined) parameters.set('quality', String(quality));\n const optimizerUrl = `/_gigadrive/image/${encodeURIComponent(stableSrc)}/${encodeURIComponent(filenameHint(stableSrc))}?${parameters}`;\n return optimizerUrl.length > MAXIMUM_OPTIMIZER_URL_LENGTH ? src : optimizerUrl;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,IAAM,iBAAiB,CAAC,WACtB,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU,IAAI,IAAI,IAAI,MAAM,EAAE,WAAW,OAAO,MAAM,QAAQ,CAAC,EAAE,CAAC;AAEtH,IAAM,eAAe,CAAC,WAA2B;AAC/C,QAAM,YAAY,eAAe,MAAM,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,GAAG,EAAE,KAAK;AAC9E,SAAO,gEAAgE,KAAK,SAAS,IACjF,YACA,GAAG,aAAa,OAAO;AAC7B;AAEA,IAAM,cAAc,CAAC,WAA4B,UAAU,KAAK,eAAe,MAAM,CAAC;AAKtF,IAAM,+BAA+B;AAYrC,IAAM,wBAAwB,CAAC,QAAwB;AACrD,MAAI,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,EAAG,QAAO;AACvD,QAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,KAAK,CAAC;AAC1C,QAAM,aAAa,IAAI,gBAAgB,KAAK;AAC5C,aAAW,OAAO,KAAK;AACvB,QAAM,YAAY,WAAW,SAAS;AACtC,SAAO,YAAY,GAAG,QAAQ,IAAI,SAAS,KAAK;AAClD;AAGe,SAAR,yBAA0C,EAAE,KAAK,OAAO,QAAQ,GAAmC;AAMxG,MAAI,YAAY,GAAG,EAAG,QAAO;AAE7B,QAAM,YAAY,sBAAsB,GAAG;AAC3C,QAAM,aAAa,IAAI,gBAAgB,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;AAC/D,MAAI,YAAY,OAAW,YAAW,IAAI,WAAW,OAAO,OAAO,CAAC;AACpE,QAAM,eAAe,qBAAqB,mBAAmB,SAAS,CAAC,IAAI,mBAAmB,aAAa,SAAS,CAAC,CAAC,IAAI,UAAU;AACpI,SAAO,aAAa,SAAS,+BAA+B,MAAM;AACpE;","names":[]}
@@ -1,9 +1,10 @@
1
1
  // src/nextjs-image-loader.ts
2
+ var sourcePathname = (source) => source.startsWith("http://") || source.startsWith("https://") ? new URL(source).pathname : source.split(/[?#]/, 1)[0];
2
3
  var filenameHint = (source) => {
3
- const pathname = source.startsWith("http://") || source.startsWith("https://") ? new URL(source).pathname : source;
4
- const candidate = pathname.split("/").filter(Boolean).at(-1)?.split("?")[0] ?? "image";
4
+ const candidate = sourcePathname(source).split("/").filter(Boolean).at(-1) ?? "image";
5
5
  return /\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate) ? candidate : `${candidate || "image"}.png`;
6
6
  };
7
+ var isSvgSource = (source) => /\.svg$/i.test(sourcePathname(source));
7
8
  var MAXIMUM_OPTIMIZER_URL_LENGTH = 2e3;
8
9
  var stripDeploymentMarker = (src) => {
9
10
  if (!src.startsWith("/") || !src.includes("?")) return src;
@@ -14,6 +15,7 @@ var stripDeploymentMarker = (src) => {
14
15
  return remaining ? `${pathname}?${remaining}` : pathname;
15
16
  };
16
17
  function gigadriveNextImageLoader({ src, width, quality }) {
18
+ if (isSvgSource(src)) return src;
17
19
  const stableSrc = stripDeploymentMarker(src);
18
20
  const parameters = new URLSearchParams({ width: String(width) });
19
21
  if (quality !== void 0) parameters.set("quality", String(quality));
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nextjs-image-loader.ts"],"sourcesContent":["interface NextImageLoaderOptions {\n src: string;\n width: number;\n quality?: number;\n}\n\nconst filenameHint = (source: string): string => {\n const pathname = source.startsWith('http://') || source.startsWith('https://') ? new URL(source).pathname : source;\n const candidate = pathname.split('/').filter(Boolean).at(-1)?.split('?')[0] ?? 'image';\n return /\\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate)\n ? candidate\n : `${candidate || 'image'}.png`;\n};\n\n// Conservative bound below common CDN/proxy URL limits (~4-8 KB). The encoded\n// source is embedded in the optimizer path, so an oversized source URL cannot\n// be shortened losslessly — such images are served unoptimized instead.\nconst MAXIMUM_OPTIMIZER_URL_LENGTH = 2000;\n\n/**\n * Removes Next's `dpl` deployment marker from a local source.\n *\n * Next appends `?dpl=<deploymentId>` to local asset sources whenever a\n * deployment id is configured. The Gigadrive optimizer resolves the deployment\n * from the request hostname and never reads `dpl`, so keeping it only changes\n * the optimizer URL on every deploy — invalidating the CDN's image cache for\n * files whose content-hashed names already guarantee freshness, and forcing a\n * full re-optimization burst after each release.\n */\nconst stripDeploymentMarker = (src: string): string => {\n if (!src.startsWith('/') || !src.includes('?')) return src;\n const [pathname, query] = src.split('?', 2);\n const parameters = new URLSearchParams(query);\n parameters.delete('dpl');\n const remaining = parameters.toString();\n return remaining ? `${pathname}?${remaining}` : pathname;\n};\n\n/** Builds the stable app-host URL consumed by Gigadrive's managed image optimizer. */\nexport default function gigadriveNextImageLoader({ src, width, quality }: NextImageLoaderOptions): string {\n const stableSrc = stripDeploymentMarker(src);\n const parameters = new URLSearchParams({ width: String(width) });\n if (quality !== undefined) parameters.set('quality', String(quality));\n const optimizerUrl = `/_gigadrive/image/${encodeURIComponent(stableSrc)}/${encodeURIComponent(filenameHint(stableSrc))}?${parameters}`;\n return optimizerUrl.length > MAXIMUM_OPTIMIZER_URL_LENGTH ? src : optimizerUrl;\n}\n"],"mappings":";AAMA,IAAM,eAAe,CAAC,WAA2B;AAC/C,QAAM,WAAW,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU,IAAI,IAAI,IAAI,MAAM,EAAE,WAAW;AAC5G,QAAM,YAAY,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AAC/E,SAAO,gEAAgE,KAAK,SAAS,IACjF,YACA,GAAG,aAAa,OAAO;AAC7B;AAKA,IAAM,+BAA+B;AAYrC,IAAM,wBAAwB,CAAC,QAAwB;AACrD,MAAI,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,EAAG,QAAO;AACvD,QAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,KAAK,CAAC;AAC1C,QAAM,aAAa,IAAI,gBAAgB,KAAK;AAC5C,aAAW,OAAO,KAAK;AACvB,QAAM,YAAY,WAAW,SAAS;AACtC,SAAO,YAAY,GAAG,QAAQ,IAAI,SAAS,KAAK;AAClD;AAGe,SAAR,yBAA0C,EAAE,KAAK,OAAO,QAAQ,GAAmC;AACxG,QAAM,YAAY,sBAAsB,GAAG;AAC3C,QAAM,aAAa,IAAI,gBAAgB,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;AAC/D,MAAI,YAAY,OAAW,YAAW,IAAI,WAAW,OAAO,OAAO,CAAC;AACpE,QAAM,eAAe,qBAAqB,mBAAmB,SAAS,CAAC,IAAI,mBAAmB,aAAa,SAAS,CAAC,CAAC,IAAI,UAAU;AACpI,SAAO,aAAa,SAAS,+BAA+B,MAAM;AACpE;","names":[]}
1
+ {"version":3,"sources":["../src/nextjs-image-loader.ts"],"sourcesContent":["interface NextImageLoaderOptions {\n src: string;\n width: number;\n quality?: number;\n}\n\n/** The path portion of a source, with any query string or fragment removed. */\nconst sourcePathname = (source: string): string =>\n source.startsWith('http://') || source.startsWith('https://') ? new URL(source).pathname : source.split(/[?#]/, 1)[0];\n\nconst filenameHint = (source: string): string => {\n const candidate = sourcePathname(source).split('/').filter(Boolean).at(-1) ?? 'image';\n return /\\.(?:avif|bmp|gif|hei[cf]|jpe?g|pbm|png|svg|tga|tiff?|webp)$/i.test(candidate)\n ? candidate\n : `${candidate || 'image'}.png`;\n};\n\nconst isSvgSource = (source: string): boolean => /\\.svg$/i.test(sourcePathname(source));\n\n// Conservative bound below common CDN/proxy URL limits (~4-8 KB). The encoded\n// source is embedded in the optimizer path, so an oversized source URL cannot\n// be shortened losslessly — such images are served unoptimized instead.\nconst MAXIMUM_OPTIMIZER_URL_LENGTH = 2000;\n\n/**\n * Removes Next's `dpl` deployment marker from a local source.\n *\n * Next appends `?dpl=<deploymentId>` to local asset sources whenever a\n * deployment id is configured. The Gigadrive optimizer resolves the deployment\n * from the request hostname and never reads `dpl`, so keeping it only changes\n * the optimizer URL on every deploy — invalidating the CDN's image cache for\n * files whose content-hashed names already guarantee freshness, and forcing a\n * full re-optimization burst after each release.\n */\nconst stripDeploymentMarker = (src: string): string => {\n if (!src.startsWith('/') || !src.includes('?')) return src;\n const [pathname, query] = src.split('?', 2);\n const parameters = new URLSearchParams(query);\n parameters.delete('dpl');\n const remaining = parameters.toString();\n return remaining ? `${pathname}?${remaining}` : pathname;\n};\n\n/** Builds the stable app-host URL consumed by Gigadrive's managed image optimizer. */\nexport default function gigadriveNextImageLoader({ src, width, quality }: NextImageLoaderOptions): string {\n // No optimizer backend can rasterize SVG, so routing one through the optimizer\n // is always a pass-through: a wasted redirect and an extra request for bytes\n // the origin already serves. Next's own get-img-props marks `.svg` unoptimized\n // before any loader runs, but that bypass is skipped once a custom loaderFile\n // is configured — which is exactly what this adapter injects.\n if (isSvgSource(src)) return src;\n\n const stableSrc = stripDeploymentMarker(src);\n const parameters = new URLSearchParams({ width: String(width) });\n if (quality !== undefined) parameters.set('quality', String(quality));\n const optimizerUrl = `/_gigadrive/image/${encodeURIComponent(stableSrc)}/${encodeURIComponent(filenameHint(stableSrc))}?${parameters}`;\n return optimizerUrl.length > MAXIMUM_OPTIMIZER_URL_LENGTH ? src : optimizerUrl;\n}\n"],"mappings":";AAOA,IAAM,iBAAiB,CAAC,WACtB,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU,IAAI,IAAI,IAAI,MAAM,EAAE,WAAW,OAAO,MAAM,QAAQ,CAAC,EAAE,CAAC;AAEtH,IAAM,eAAe,CAAC,WAA2B;AAC/C,QAAM,YAAY,eAAe,MAAM,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,GAAG,EAAE,KAAK;AAC9E,SAAO,gEAAgE,KAAK,SAAS,IACjF,YACA,GAAG,aAAa,OAAO;AAC7B;AAEA,IAAM,cAAc,CAAC,WAA4B,UAAU,KAAK,eAAe,MAAM,CAAC;AAKtF,IAAM,+BAA+B;AAYrC,IAAM,wBAAwB,CAAC,QAAwB;AACrD,MAAI,CAAC,IAAI,WAAW,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,EAAG,QAAO;AACvD,QAAM,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,KAAK,CAAC;AAC1C,QAAM,aAAa,IAAI,gBAAgB,KAAK;AAC5C,aAAW,OAAO,KAAK;AACvB,QAAM,YAAY,WAAW,SAAS;AACtC,SAAO,YAAY,GAAG,QAAQ,IAAI,SAAS,KAAK;AAClD;AAGe,SAAR,yBAA0C,EAAE,KAAK,OAAO,QAAQ,GAAmC;AAMxG,MAAI,YAAY,GAAG,EAAG,QAAO;AAE7B,QAAM,YAAY,sBAAsB,GAAG;AAC3C,QAAM,aAAa,IAAI,gBAAgB,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;AAC/D,MAAI,YAAY,OAAW,YAAW,IAAI,WAAW,OAAO,OAAO,CAAC;AACpE,QAAM,eAAe,qBAAqB,mBAAmB,SAAS,CAAC,IAAI,mBAAmB,aAAa,SAAS,CAAC,CAAC,IAAI,UAAU;AACpI,SAAO,aAAa,SAAS,+BAA+B,MAAM;AACpE;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gigadrive/network-config",
3
- "version": "4.3.1",
3
+ "version": "4.3.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/Gigadrive/sdk.git",