| import 'server-only'; |
| import { renderToReadableStream } from 'react-server-dom-webpack/server'; |
| import { createFromReadableStream } from 'react-server-dom-webpack/client'; |
| import { streamToString } from '../stream-utils/node-web-streams-helper'; |
| import { arrayBufferToString, decrypt, encrypt, getActionEncryptionKey, getClientReferenceManifestForRsc, getServerModuleMap, stringToUint8Array } from './encryption-utils'; |
| import { getCacheSignal, getPrerenderResumeDataCache, getRenderResumeDataCache, workUnitAsyncStorage } from './work-unit-async-storage.external'; |
| import { createHangingInputAbortSignal } from './dynamic-rendering'; |
| import React from 'react'; |
| const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge'; |
| const textEncoder = new TextEncoder(); |
| const textDecoder = new TextDecoder(); |
| const filterStackFrame = process.env.NODE_ENV !== 'production' ? require('../lib/source-maps').filterStackFrameDEV : undefined; |
| const findSourceMapURL = process.env.NODE_ENV !== 'production' ? require('../lib/source-maps').findSourceMapURLDEV : undefined; |
| |
| |
| async function decodeActionBoundArg(actionId, arg) { |
| const key = await getActionEncryptionKey(); |
| if (typeof key === 'undefined') { |
| throw Object.defineProperty(new Error(`Missing encryption key for Server Action. This is a bug in Next.js`), "__NEXT_ERROR_CODE", { |
| value: "E65", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| |
| const originalPayload = atob(arg); |
| const ivValue = originalPayload.slice(0, 16); |
| const payload = originalPayload.slice(16); |
| const decrypted = textDecoder.decode(await decrypt(key, stringToUint8Array(ivValue), stringToUint8Array(payload))); |
| if (!decrypted.startsWith(actionId)) { |
| throw Object.defineProperty(new Error('Invalid Server Action payload: failed to decrypt.'), "__NEXT_ERROR_CODE", { |
| value: "E191", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| return decrypted.slice(actionId.length); |
| } |
| |
| |
| |
| async function encodeActionBoundArg(actionId, arg) { |
| const key = await getActionEncryptionKey(); |
| if (key === undefined) { |
| throw Object.defineProperty(new Error(`Missing encryption key for Server Action. This is a bug in Next.js`), "__NEXT_ERROR_CODE", { |
| value: "E65", |
| enumerable: false, |
| configurable: true |
| }); |
| } |
| |
| const randomBytes = new Uint8Array(16); |
| workUnitAsyncStorage.exit(()=>crypto.getRandomValues(randomBytes)); |
| const ivValue = arrayBufferToString(randomBytes.buffer); |
| const encrypted = await encrypt(key, randomBytes, textEncoder.encode(actionId + arg)); |
| return btoa(ivValue + arrayBufferToString(encrypted)); |
| } |
| var ReadStatus = function(ReadStatus) { |
| ReadStatus[ReadStatus["Ready"] = 0] = "Ready"; |
| ReadStatus[ReadStatus["Pending"] = 1] = "Pending"; |
| ReadStatus[ReadStatus["Complete"] = 2] = "Complete"; |
| return ReadStatus; |
| }(ReadStatus || {}); |
| |
| |
| |
| |
| export const encryptActionBoundArgs = React.cache(async function encryptActionBoundArgs(actionId, ...args) { |
| const workUnitStore = workUnitAsyncStorage.getStore(); |
| const cacheSignal = workUnitStore ? getCacheSignal(workUnitStore) : undefined; |
| const { clientModules } = getClientReferenceManifestForRsc(); |
| |
| |
| const error = new Error(); |
| Error.captureStackTrace(error, encryptActionBoundArgs); |
| let didCatchError = false; |
| const hangingInputAbortSignal = workUnitStore ? createHangingInputAbortSignal(workUnitStore) : undefined; |
| let readStatus = 0; |
| function startReadOnce() { |
| if (readStatus === 0) { |
| readStatus = 1; |
| cacheSignal == null ? void 0 : cacheSignal.beginRead(); |
| } |
| } |
| function endReadIfStarted() { |
| if (readStatus === 1) { |
| cacheSignal == null ? void 0 : cacheSignal.endRead(); |
| } |
| readStatus = 2; |
| } |
| |
| |
| |
| |
| |
| |
| if (hangingInputAbortSignal && cacheSignal) { |
| hangingInputAbortSignal.addEventListener('abort', startReadOnce, { |
| once: true |
| }); |
| } |
| |
| const serialized = await streamToString(renderToReadableStream(args, clientModules, { |
| filterStackFrame, |
| signal: hangingInputAbortSignal, |
| onError (err) { |
| if (hangingInputAbortSignal == null ? void 0 : hangingInputAbortSignal.aborted) { |
| return; |
| } |
| |
| if (didCatchError) { |
| return; |
| } |
| didCatchError = true; |
| |
| |
| error.message = err instanceof Error ? err.message : String(err); |
| } |
| }), |
| |
| |
| hangingInputAbortSignal); |
| if (didCatchError) { |
| if (process.env.NODE_ENV === 'development') { |
| |
| |
| |
| console.error(error); |
| } |
| endReadIfStarted(); |
| throw error; |
| } |
| if (!workUnitStore) { |
| |
| |
| return encodeActionBoundArg(actionId, serialized); |
| } |
| startReadOnce(); |
| const prerenderResumeDataCache = getPrerenderResumeDataCache(workUnitStore); |
| const renderResumeDataCache = getRenderResumeDataCache(workUnitStore); |
| const cacheKey = actionId + serialized; |
| const cachedEncrypted = (prerenderResumeDataCache == null ? void 0 : prerenderResumeDataCache.encryptedBoundArgs.get(cacheKey)) ?? (renderResumeDataCache == null ? void 0 : renderResumeDataCache.encryptedBoundArgs.get(cacheKey)); |
| if (cachedEncrypted) { |
| return cachedEncrypted; |
| } |
| const encrypted = await encodeActionBoundArg(actionId, serialized); |
| endReadIfStarted(); |
| prerenderResumeDataCache == null ? void 0 : prerenderResumeDataCache.encryptedBoundArgs.set(cacheKey, encrypted); |
| return encrypted; |
| }); |
| |
| export async function decryptActionBoundArgs(actionId, encryptedPromise) { |
| const encrypted = await encryptedPromise; |
| const workUnitStore = workUnitAsyncStorage.getStore(); |
| let decrypted; |
| if (workUnitStore) { |
| const cacheSignal = getCacheSignal(workUnitStore); |
| const prerenderResumeDataCache = getPrerenderResumeDataCache(workUnitStore); |
| const renderResumeDataCache = getRenderResumeDataCache(workUnitStore); |
| decrypted = (prerenderResumeDataCache == null ? void 0 : prerenderResumeDataCache.decryptedBoundArgs.get(encrypted)) ?? (renderResumeDataCache == null ? void 0 : renderResumeDataCache.decryptedBoundArgs.get(encrypted)); |
| if (!decrypted) { |
| cacheSignal == null ? void 0 : cacheSignal.beginRead(); |
| decrypted = await decodeActionBoundArg(actionId, encrypted); |
| cacheSignal == null ? void 0 : cacheSignal.endRead(); |
| prerenderResumeDataCache == null ? void 0 : prerenderResumeDataCache.decryptedBoundArgs.set(encrypted, decrypted); |
| } |
| } else { |
| decrypted = await decodeActionBoundArg(actionId, encrypted); |
| } |
| const { edgeRscModuleMapping, rscModuleMapping } = getClientReferenceManifestForRsc(); |
| |
| const deserialized = await createFromReadableStream(new ReadableStream({ |
| start (controller) { |
| controller.enqueue(textEncoder.encode(decrypted)); |
| switch(workUnitStore == null ? void 0 : workUnitStore.type){ |
| case 'prerender': |
| case 'prerender-runtime': |
| |
| |
| if (workUnitStore.renderSignal.aborted) { |
| controller.close(); |
| } else { |
| workUnitStore.renderSignal.addEventListener('abort', ()=>controller.close(), { |
| once: true |
| }); |
| } |
| break; |
| case 'prerender-client': |
| case 'prerender-ppr': |
| case 'prerender-legacy': |
| case 'request': |
| case 'cache': |
| case 'private-cache': |
| case 'unstable-cache': |
| case undefined: |
| return controller.close(); |
| default: |
| workUnitStore; |
| } |
| } |
| }), { |
| findSourceMapURL, |
| serverConsumerManifest: { |
| |
| |
| |
| moduleLoading: null, |
| moduleMap: isEdgeRuntime ? edgeRscModuleMapping : rscModuleMapping, |
| serverModuleMap: getServerModuleMap() |
| } |
| }); |
| return deserialized; |
| } |
|
|
| |