eve 0.26.2 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/src/harness/compaction-prompt.d.ts +19 -1
- package/dist/src/harness/compaction-prompt.js +7 -5
- package/dist/src/harness/compaction.d.ts +4 -11
- package/dist/src/harness/compaction.js +1 -1
- package/dist/src/harness/prompt-cache.d.ts +16 -5
- package/dist/src/harness/prompt-cache.js +1 -1
- package/dist/src/harness/token-estimate.d.ts +9 -0
- package/dist/src/harness/token-estimate.js +1 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/copy-host-middleware.js +1 -1
- package/dist/src/public/channels/auth.d.ts +59 -9
- package/dist/src/public/channels/auth.js +1 -1
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/nuxt/index.d.ts +1 -1
- package/dist/src/public/nuxt/index.js +1 -1
- package/dist/src/public/nuxt/module.d.ts +10 -24
- package/dist/src/public/nuxt/module.js +1 -1
- package/dist/src/public/nuxt/routing.d.ts +5 -39
- package/dist/src/public/nuxt/routing.js +1 -1
- package/dist/src/public/nuxt/vercel-services.d.ts +117 -0
- package/dist/src/public/nuxt/vercel-services.js +1 -0
- package/dist/src/runtime/framework-tools/todo.js +1 -1
- package/dist/src/runtime/governance/auth/http-basic.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/{public/next → shared}/resolve-eve-binary.d.ts +1 -1
- package/docs/extensions.md +115 -77
- package/docs/guides/auth-and-route-protection.md +14 -1
- package/docs/guides/frontend/nuxt.mdx +22 -1
- package/docs/meta.json +1 -0
- package/package.json +1 -1
- package/dist/src/public/nuxt/vercel-json.d.ts +0 -17
- package/dist/src/public/nuxt/vercel-json.js +0 -1
- /package/dist/src/{public/next → shared}/resolve-eve-binary.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1db41fd: `eve/nuxt` now deploys the agent through Vercel's stable services model: on Vercel builds the module generates an eve Build Output service and a `/eve/v1/*` service route instead of writing legacy `experimentalServices` to `vercel.json`, which Vercel no longer routes (every agent request returned a platform NOT_FOUND). The `configureVercelJson` and `servicePrefix` module options and the `EVE_NUXT_SERVICE_PREFIX` export were removed. Delete any generated `experimentalServices` block from `vercel.json` — the module warns when it sees one — or declare the eve service and its rewrite yourself under the stable `services` field to keep managing routing manually.
|
|
8
|
+
|
|
9
|
+
A generated eve service build now also skips host middleware preservation when the host's Build Output config is not yet present, instead of failing the build. Unlike the Next.js integration, which writes that config early, the Nuxt web service emits it only at the end of its own build, so an isolated eve service build could crash reading a file that had no middleware to preserve.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 707de7f: Anthropic models served through the standard `@ai-sdk/amazon-bedrock` Converse provider are now detected as cacheable. Prompt-cache breakpoints previously only matched on the provider name, so Bedrock (which reports provider `amazon-bedrock` and carries the Anthropic identity in the model id) fell through to no caching. The cache marker now also carries the Bedrock `cachePoint` namespace that the Converse provider reads.
|
|
14
|
+
- 7df0bf1: Compaction now reserves room for its checkpoint prompt before reaching the configured threshold. The prompt asks the compaction model to distinguish completed work from remaining work, and later compactions receive the previous checkpoint intact instead of truncating it with ordinary transcript text.
|
|
15
|
+
- 7df0bf1: Compaction now feeds the summarizer full-fidelity conversation text (tool payloads stay compact) and first tries evicting older tool results before summarizing; the kept recent window retains tool results verbatim. Agents lose less context per compaction and stop re-running completed tools.
|
|
16
|
+
- c0e368a: Routes protected by `httpBasic()` now advertise a standards-compliant `WWW-Authenticate: Basic` challenge on 401, using an optional realm that defaults to `"eve"`; HTTP Basic credentials are normalized to Unicode NFC to match the advertised UTF-8 encoding. `routeAuth` collects challenges from the configured auth strategies instead of always emitting `Bearer`.
|
|
17
|
+
|
|
3
18
|
## 0.26.2
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { ModelMessage } from "ai";
|
|
2
2
|
export declare const COMPACTION_CHECKPOINT_MARKER = "Summary of our conversation so far:";
|
|
3
|
+
/** Synthetic resumption prompt used when no real user message can be replayed. */
|
|
4
|
+
export declare const COMPACTION_RESUMPTION_MESSAGE = "Continue.";
|
|
5
|
+
/**
|
|
6
|
+
* Label line of the framework-injected todo preservation message. Owned here
|
|
7
|
+
* so compaction can recognize the message as synthetic when picking a user
|
|
8
|
+
* message to replay after compaction.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TODO_COMPACTION_PRESERVATION_LABEL = "[Your task list was preserved across context compaction]";
|
|
3
11
|
export interface CompactionPrompt {
|
|
4
12
|
readonly prompt: string;
|
|
5
13
|
readonly system: string;
|
|
@@ -9,8 +17,18 @@ export declare const COMPACTION_PROMPT_ENVELOPE: {
|
|
|
9
17
|
prompt: string;
|
|
10
18
|
system: string;
|
|
11
19
|
};
|
|
12
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Builds the compaction model input from framework-owned checkpoint state and
|
|
22
|
+
* older messages.
|
|
23
|
+
*
|
|
24
|
+
* Conversational text is rendered verbatim. When `transcriptBudgetTokens` is
|
|
25
|
+
* set and the rendered prompt exceeds it, conversational text is capped at
|
|
26
|
+
* {@link DEGRADED_TEXT_LIMIT} starting from the oldest entries until the
|
|
27
|
+
* prompt fits; the previous checkpoint is never truncated.
|
|
28
|
+
*/
|
|
13
29
|
export declare function createCompactionPrompt(input: {
|
|
14
30
|
readonly messages: readonly ModelMessage[];
|
|
15
31
|
readonly previousCheckpoint: string | undefined;
|
|
32
|
+
readonly transcriptBudgetTokens?: number;
|
|
16
33
|
}): CompactionPrompt;
|
|
34
|
+
export declare const TRANSCRIPT_PAYLOAD_LIMIT = 2000;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const COMPACTION_CHECKPOINT_MARKER=`Summary of our conversation so far:`,COMPACTION_SYSTEM_PROMPT=`You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.
|
|
1
|
+
import{estimateTokens}from"#harness/token-estimate.js";const COMPACTION_CHECKPOINT_MARKER=`Summary of our conversation so far:`,COMPACTION_RESUMPTION_MESSAGE=`Continue.`,TODO_COMPACTION_PRESERVATION_LABEL=`[Your task list was preserved across context compaction]`,COMPACTION_SYSTEM_PROMPT=`You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.
|
|
2
2
|
|
|
3
3
|
Include:
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ Include:
|
|
|
7
7
|
- What remains to be done, with clear next steps
|
|
8
8
|
- Any critical data, examples, or references needed to continue
|
|
9
9
|
|
|
10
|
-
Be concise, structured, and focused on helping the next LLM seamlessly continue the work. Write in the same language as the conversation. Do not continue the conversation, answer its questions, or invent facts. Only output the handoff summary.`,COMPACTION_PROMPT_ENVELOPE={prompt:formatCompactionPrompt({previousCheckpoint:``,transcript:``}),system:COMPACTION_SYSTEM_PROMPT};function createCompactionPrompt(e){let
|
|
10
|
+
Be concise, structured, and focused on helping the next LLM seamlessly continue the work. Write in the same language as the conversation. Do not continue the conversation, answer its questions, or invent facts. Only output the handoff summary.`,COMPACTION_PROMPT_ENVELOPE={prompt:formatCompactionPrompt({previousCheckpoint:``,transcript:``}),system:COMPACTION_SYSTEM_PROMPT};function createCompactionPrompt(e){let t=e.messages.map(e=>({content:renderCompactionMessageContent(e),role:e.role}));return degradeOversizedTranscript(e,t),{prompt:formatCompactionPrompt({previousCheckpoint:e.previousCheckpoint?.trim()??`(none)`,transcript:formatCompactionTranscript(t)}),system:COMPACTION_SYSTEM_PROMPT}}function degradeOversizedTranscript(t,n){let r=t.transcriptBudgetTokens;if(r===void 0)return;let i=estimateTokens(formatCompactionPrompt({previousCheckpoint:t.previousCheckpoint?.trim()??`(none)`,transcript:formatCompactionTranscript(n)}))-r;for(let e=0;e<n.length&&i>0;e+=1){let r=n[e],a=t.messages[e];if(r===void 0||a===void 0)continue;let o=renderCompactionMessageContent(a,2e3);o.length>=r.content.length||(i-=(r.content.length-o.length)/4,n[e]={content:o,role:r.role})}}function formatCompactionPrompt(e){return`<previous-checkpoint>
|
|
11
11
|
${e.previousCheckpoint}
|
|
12
12
|
</previous-checkpoint>
|
|
13
13
|
|
|
@@ -18,7 +18,9 @@ ${e.transcript}
|
|
|
18
18
|
|
|
19
19
|
Update the previous checkpoint with the newer information in the conversation. If there is no previous checkpoint, create one from the conversation.
|
|
20
20
|
|
|
21
|
-
Make completed work explicit so the next model does not repeat it. Keep completed work separate from current and remaining work, and do not describe completed work as pending unless later messages show it must be redone. Preserve exact file paths, function names, commands, error messages, identifiers, and measured values when they are needed to continue
|
|
21
|
+
Make completed work explicit so the next model does not repeat it. Keep completed work separate from current and remaining work, and do not describe completed work as pending unless later messages show it must be redone. Preserve exact file paths, function names, commands, error messages, identifiers, and measured values when they are needed to continue.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
Large tool outputs are the main thing to compress: reduce each to the findings the next model needs — what was searched or read, what it established, and the exact identifiers involved — rather than reproducing the output. The next model cannot see the originals, so nothing it would need to act on may be lost.`}function formatCompactionTranscript(e){let t=e.filter(e=>e.content.trim().length>0).map(e=>`### ${e.role}\n${e.content.trim()}`);return t.length===0?`(empty)`:t.join(`
|
|
24
|
+
|
|
25
|
+
`)}function renderCompactionMessageContent(e,t){return typeof e.content==`string`?renderConversationText(e.content,t):e.content.map(e=>renderCompactionContentPart(e,t)).filter(e=>e.length>0).join(`
|
|
26
|
+
`).trim()}function renderCompactionContentPart(e,t){switch(e.type){case`text`:return renderConversationText(e.text,t);case`reasoning`:return``;case`file`:return e.filename?`Attached file ${e.filename} (${e.mediaType})`:`Attached file attachment (${e.mediaType})`;case`tool-call`:return renderTranscriptToolCall(e,t);case`tool-result`:return renderTranscriptToolResult(e,t);default:return``}}const TRANSCRIPT_PAYLOAD_LIMIT=2e3;function renderTranscriptToolCall(e,t){return renderToolCall(e,t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280)}function renderTranscriptToolResult(e,t){let n=t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280,r=e.isError?`errored`:`returned`,i=renderPayload(e.output,n);return i?`Tool ${e.toolName} ${r} ${i}`:`Tool ${e.toolName} ${r}`}function renderToolCall(e,t){let n=renderPayload(e.input,t);return n?`Called ${e.toolName} with ${n}`:`Called ${e.toolName}`}function renderPayload(e,t){return e===void 0?``:capText(JSON.stringify(e)??``,t)}function renderConversationText(e,t){return t===void 0?e.trim():capText(e,t)}function capText(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length<=t?n:`${n.slice(0,t).trimEnd()}…`}export{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TODO_COMPACTION_PRESERVATION_LABEL,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt};
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import { generateText, type LanguageModel, type ModelMessage, type TelemetryOptions } from "ai";
|
|
2
2
|
import type { RuntimeModelReference } from "#runtime/agent/bootstrap.js";
|
|
3
3
|
import type { CompactionConfig, ToolLoopHarnessConfig } from "#harness/types.js";
|
|
4
|
-
/**
|
|
5
|
-
* Rough token estimate: serialized JSON length / 4. Good enough for
|
|
6
|
-
* deciding whether compaction is needed; the real token count comes back
|
|
7
|
-
* from the model each step via {@link CompactionConfig.lastKnownInputTokens}.
|
|
8
|
-
*
|
|
9
|
-
* Accepts any JSON-serializable value so callers can apply the same heuristic
|
|
10
|
-
* to whole message arrays or individual content parts on one consistent ruler.
|
|
11
|
-
*/
|
|
12
|
-
export declare function estimateTokens(value: unknown): number;
|
|
13
4
|
/**
|
|
14
5
|
* Best available input-token count: the model-reported count from the last
|
|
15
6
|
* step, plus a rough character-based estimate of whatever messages have been
|
|
@@ -37,7 +28,9 @@ export declare function resolveCompactionModel(input: {
|
|
|
37
28
|
readonly providerOptions: Parameters<typeof generateText>[0]["providerOptions"];
|
|
38
29
|
}>;
|
|
39
30
|
/**
|
|
40
|
-
* Compacts messages by
|
|
41
|
-
*
|
|
31
|
+
* Compacts messages by escalation: try each {@link CompactionHeuristic} in
|
|
32
|
+
* order, then fall back to summarizing the older region with the compaction
|
|
33
|
+
* model — keeping the recent tail verbatim when it fits, degrading it to
|
|
34
|
+
* text-only, then shrinking the window.
|
|
42
35
|
*/
|
|
43
36
|
export declare function compactMessages(messages: ModelMessage[], model: LanguageModel, config: CompactionConfig, providerOptions?: Parameters<typeof generateText>[0]["providerOptions"], telemetry?: TelemetryOptions, headers?: Record<string, string>, abortSignal?: AbortSignal): Promise<ModelMessage[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{generateText}from"ai";import{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,createCompactionPrompt}from"#harness/compaction-prompt.js";
|
|
1
|
+
import{generateText}from"ai";import{estimateTokens}from"#harness/token-estimate.js";import{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TODO_COMPACTION_PRESERVATION_LABEL,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt}from"#harness/compaction-prompt.js";const COMPACTION_PROMPT_OVERHEAD_TOKENS=estimateTokens([{content:COMPACTION_PROMPT_ENVELOPE.system,role:`system`},{content:COMPACTION_PROMPT_ENVELOPE.prompt,role:`user`}]);function getInputTokenCount(e,n){let r=n.lastKnownInputTokens,i=n.lastKnownPromptMessageCount;return r===void 0||i===void 0||!Number.isInteger(i)||i<0||i>e.length?estimateTokens(e):r+estimateTokens(e.slice(i))}function shouldCompact(e,t){return e.length>0&&getInputTokenCount(e,t)+COMPACTION_PROMPT_OVERHEAD_TOKENS>t.threshold}async function resolveCompactionModel(e){let t=e.compactionModelReference??e.modelReference;return{model:t===e.modelReference?e.model:await e.resolveModel(t),providerOptions:t.providerOptions}}const COMPACTION_HEURISTICS=[toolResultCapHeuristic];function toolResultCapHeuristic(e){let t=withResumptionGuard([...e.previousCheckpoint===void 0?[]:[{content:COMPACTION_CHECKPOINT_MARKER,role:`user`},{content:e.previousCheckpoint,role:`assistant`}],...capToolResults(e.older),...e.recent],e.conversation);return evaluateThreshold(t,e.config,`should-compact`).type===`within-limit`?{messages:t,type:`within-limit`}:{type:`insufficient`}}function evaluateThreshold(e,n,r){let i=r===`should-compact`?COMPACTION_PROMPT_OVERHEAD_TOKENS:0,a=estimateTokens(e)+i;return{estimatedTokens:a,type:a<=n.threshold?`within-limit`:`over-limit`}}async function compactMessages(t,r,i,a,o,c,u){let{conversation:d,previousCheckpoint:f}=extractPreviousCheckpoint(t),p=selectRecentWindowSize(d,i);{let{older:e,recent:t}=splitMessagesForCompaction(d,p);if(e.length===0&&f===void 0)return keepNonToolResultMessages(t);for(let n of COMPACTION_HEURISTICS){let r=n({config:i,conversation:d,older:e,previousCheckpoint:f,recent:t});if(r.type===`within-limit`)return r.messages}}for(;;){let{older:t,recent:l}=splitMessagesForCompaction(d,p),m=createCompactionPrompt({messages:t,previousCheckpoint:f,transcriptBudgetTokens:i.threshold}),h=await generateText({abortSignal:u,headers:c,model:r,prompt:m.prompt,providerOptions:a,system:m.system,telemetry:o?{...o,functionId:`eve.compaction`}:void 0,temperature:0}),g=[{content:COMPACTION_CHECKPOINT_MARKER,role:`user`},{content:h.text,role:`assistant`}],_=withResumptionGuard([...g,...l],d);if(evaluateThreshold(_,i,`estimate`).type===`within-limit`)return _;let v=withResumptionGuard([...g,...keepNonToolResultMessages(l)],d);if(evaluateThreshold(v,i,`estimate`).type===`within-limit`||p===0)return v;--p}}function capToolResults(e){return e.map(e=>{if(e.role!==`tool`||typeof e.content==`string`)return e;let t=!1,n=e.content.map(e=>{if(e.type!==`tool-result`)return e;let n=JSON.stringify(e.output)??``;return n.length<=TRANSCRIPT_PAYLOAD_LIMIT?e:(t=!0,{...e,output:{type:`text`,value:`[Truncated by eve: tool result reduced during context compaction. Re-run the tool if you need the full output.]\n\n${n.slice(0,TRANSCRIPT_PAYLOAD_LIMIT)}`}})});return t?{...e,content:n}:e})}function withResumptionGuard(e,t){let n=e.at(-1)?.role;if(n!==void 0&&n!==`assistant`)return e;let r=findLastRealUserMessage(t),a=r!==void 0&&e.some(e=>e.role===`user`&&e.content===r.content);return[...e,r!==void 0&&!a?r:{content:COMPACTION_RESUMPTION_MESSAGE,role:`user`}]}function findLastRealUserMessage(e){for(let t=e.length-1;t>=0;--t){let r=e[t];if(!(r?.role!==`user`||typeof r.content!=`string`)&&!(r.content===COMPACTION_RESUMPTION_MESSAGE||r.content===COMPACTION_CHECKPOINT_MARKER||r.content.startsWith(TODO_COMPACTION_PRESERVATION_LABEL)))return r}}function extractPreviousCheckpoint(e){let t=e[0],r=e[1];return t?.role!==`user`||t.content!==COMPACTION_CHECKPOINT_MARKER||r?.role!==`assistant`?{conversation:[...e],previousCheckpoint:void 0}:{conversation:e.slice(2),previousCheckpoint:assistantMessageText(r)}}function keepNonToolResultMessages(e){let t=[];for(let n of e)if(n.role!==`tool`){if(n.role===`assistant`){let e=assistantMessageText(n);e.length>0&&t.push({content:e,role:`assistant`});continue}t.push(n)}return t}function assistantMessageText(e){return typeof e.content==`string`?e.content.trim():e.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}function selectRecentWindowSize(e,n){let r=Math.min(n.recentWindowSize,Math.max(e.length-1,0)),i=resolveCompactionSummaryReserve(n),a=0,o=0;for(let s=e.length-1;s>=0&&a<r;--s){let r=e[s];if(r===void 0)continue;let c=estimateTokens([r]);if(o+c+i>n.threshold)break;o+=c,a+=1}return a}function resolveCompactionSummaryReserve(e){return Math.min(2048,Math.max(64,Math.floor(e.threshold/4)))}function splitMessagesForCompaction(e,t){if(t<=0)return{older:[...e],recent:[]};let n=e.length-t;for(;n<e.length&&e[n]?.role===`tool`;)n+=1;return{older:e.slice(0,n),recent:e.slice(n)}}export{compactMessages,getInputTokenCount,resolveCompactionModel,shouldCompact};
|
|
@@ -12,11 +12,17 @@ export type PromptCachePath = {
|
|
|
12
12
|
/**
|
|
13
13
|
* Cache marker injected on the Anthropic-direct path.
|
|
14
14
|
*
|
|
15
|
-
* The
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* The marker carries two provider namespaces because Anthropic models are
|
|
16
|
+
* reachable through providers that read different provider-options keys:
|
|
17
|
+
*
|
|
18
|
+
* - `anthropic.cacheControl` — read by the AI SDK Anthropic provider and by
|
|
19
|
+
* `@ai-sdk/amazon-bedrock/anthropic` and `@ai-sdk/google-vertex/anthropic`,
|
|
20
|
+
* which implement the native Anthropic Messages API.
|
|
21
|
+
* - `bedrock.cachePoint` — read by the standard `@ai-sdk/amazon-bedrock`
|
|
22
|
+
* Converse provider, which does not understand `anthropic.cacheControl`.
|
|
23
|
+
*
|
|
24
|
+
* A provider ignores namespaces it does not own, so carrying both is safe on
|
|
25
|
+
* every Anthropic-direct request regardless of which provider serves it.
|
|
20
26
|
*/
|
|
21
27
|
export interface AnthropicCacheMarker {
|
|
22
28
|
readonly anthropic: {
|
|
@@ -24,6 +30,11 @@ export interface AnthropicCacheMarker {
|
|
|
24
30
|
readonly type: "ephemeral";
|
|
25
31
|
};
|
|
26
32
|
};
|
|
33
|
+
readonly bedrock: {
|
|
34
|
+
readonly cachePoint: {
|
|
35
|
+
readonly type: "default";
|
|
36
|
+
};
|
|
37
|
+
};
|
|
27
38
|
}
|
|
28
39
|
/**
|
|
29
40
|
* Detects which prompt caching path applies to a resolved model.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const ANTHROPIC_CACHE_MARKER=Object.freeze({anthropic:Object.freeze({cacheControl:Object.freeze({type:`ephemeral`})})});function detectPromptCachePath(e){
|
|
1
|
+
const ANTHROPIC_CACHE_MARKER=Object.freeze({anthropic:Object.freeze({cacheControl:Object.freeze({type:`ephemeral`})}),bedrock:Object.freeze({cachePoint:Object.freeze({type:`default`})})});function detectPromptCachePath(e){if(typeof e==`string`)return{kind:`gateway-auto`};let t=typeof e.provider==`string`?e.provider.toLowerCase():``;if(t.includes(`anthropic`))return{kind:`anthropic-direct`};let n=typeof e.modelId==`string`?e.modelId.toLowerCase():``;return t.includes(`bedrock`)&&n.includes(`anthropic`)?{kind:`anthropic-direct`}:{kind:`none`}}function getAnthropicCacheMarker(){return ANTHROPIC_CACHE_MARKER}function mergeGatewayAutoCaching(e){let t=e?.gateway!==void 0&&typeof e.gateway==`object`&&e.gateway!==null?e.gateway:void 0,n={...t,caching:t?.caching??`auto`};return{...e,gateway:n}}function applyLastToolCacheBreakpoint(e,t){let n=Object.entries(e);if(n.length===0)return e;let r={};for(let e=0;e<n.length;e++){let[i,a]=n[e];if(e===n.length-1){let e=a.providerOptions!==void 0&&typeof a.providerOptions==`object`?a.providerOptions:void 0;r[i]={...a,providerOptions:{...e,...t}}}else r[i]=a}return r}function applySystemCacheBreakpoint(e,t){if(e.length===0)return[...e];let n=[...e],r=n[n.length-1];return n[n.length-1]={...r,providerOptions:{...r.providerOptions,...t}},n}function applyConversationCacheControl(e,t){if(e.length===0)return[...e];let n=[...e],mark=e=>{let r=n[e];r!==void 0&&(n[e]={...r,providerOptions:{...r.providerOptions,...t}})};mark(n.length-1);for(let e=n.length-2;e>=0;e--)if(n[e]?.role===`assistant`){mark(e);break}return n}export{applyConversationCacheControl,applyLastToolCacheBreakpoint,applySystemCacheBreakpoint,detectPromptCachePath,getAnthropicCacheMarker,mergeGatewayAutoCaching};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rough token estimate: serialized JSON length / 4. Good enough for
|
|
3
|
+
* deciding whether compaction is needed; the real token count comes back
|
|
4
|
+
* from the model each step via `CompactionConfig.lastKnownInputTokens`.
|
|
5
|
+
*
|
|
6
|
+
* Accepts any JSON-serializable value so callers can apply the same heuristic
|
|
7
|
+
* to whole message arrays or individual content parts on one consistent ruler.
|
|
8
|
+
*/
|
|
9
|
+
export declare function estimateTokens(value: unknown): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function estimateTokens(e){return JSON.stringify(e).length/4}export{estimateTokens};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire}from"node:module";import{existsSync,readFileSync,realpathSync}from"node:fs";import{basename,dirname,join}from"node:path";import{EVE_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const BUNDLED_FALLBACK_PACKAGE_VERSION=`0.
|
|
1
|
+
import{createRequire}from"node:module";import{existsSync,readFileSync,realpathSync}from"node:fs";import{basename,dirname,join}from"node:path";import{EVE_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const BUNDLED_FALLBACK_PACKAGE_VERSION=`0.27.0`,WORKFLOW_MODULE_ALIASES={"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`};function resolveFallbackPackageVersion(){return BUNDLED_FALLBACK_PACKAGE_VERSION.startsWith(`__`)?`0.0.0`:BUNDLED_FALLBACK_PACKAGE_VERSION}const FALLBACK_PACKAGE_INFO={name:EVE_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let n=e;for(;;){if(existsSync(join(n,`package.json`))&&!isBuildOutputPackageRoot(n))return n;let r=dirname(n);if(r===n)throw Error(`Failed to resolve package root from "${e}".`);n=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageDependencyPath(e){return require.resolve(e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let r=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(r?.name===t)return r}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),EVE_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${EVE_PACKAGE_NAME}/package.json`),EVE_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function readWorkflowVersionFromManifest(e){let t=e;for(let e of[t.devDependencies,t.dependencies,t.peerDependencies]){let t=e?.[`@workflow/core`];if(typeof t==`string`&&t.trim().length>0)return t}}function resolveExpectedWorkflowVersion(){let e=tryResolvePackageRoot();if(e!==void 0)try{return readWorkflowVersionFromManifest(JSON.parse(readFileSync(join(e,`package.json`),`utf8`)))}catch{}try{return readWorkflowVersionFromManifest(JSON.parse(readFileSync(require.resolve(`${EVE_PACKAGE_NAME}/package.json`),`utf8`)))}catch{return}}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/api`||e===`workflow/runtime`)return resolvePackageSourceFilePath(`src/internal/workflow/runtime.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveExpectedWorkflowVersion,resolveInstalledPackageInfo,resolvePackageCompiledFilePath,resolvePackageDependencyPath,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname,join,posix,resolve,sep}from"node:path";import{access,cp,mkdir,readFile}from"node:fs/promises";function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const NEXT_MIDDLEWARE_PATH=`/_middleware`;function resolveMiddlewareFunctionDirectory(e,t){let a=posix.normalize(t.replace(/^\/+/,``));if(a.length===0||a===`.`||a===`..`||a.startsWith(`../`)||a.includes(`\\`)||a.includes(`\0`))throw Error(`Invalid Vercel middlewarePath: ${JSON.stringify(t)}.`);let o=resolve(e,`functions`),s=resolve(o,`${a}.func`);if(!s.startsWith(`${o}${sep}`))throw Error(`Vercel middlewarePath escapes the functions directory: ${t}.`);return s}async function copyHostMiddlewareFunctions(n){let r=
|
|
1
|
+
import{dirname,join,posix,resolve,sep}from"node:path";import{access,cp,mkdir,readFile}from"node:fs/promises";function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const NEXT_MIDDLEWARE_PATH=`/_middleware`;function resolveMiddlewareFunctionDirectory(e,t){let a=posix.normalize(t.replace(/^\/+/,``));if(a.length===0||a===`.`||a===`..`||a.startsWith(`../`)||a.includes(`\\`)||a.includes(`\0`))throw Error(`Invalid Vercel middlewarePath: ${JSON.stringify(t)}.`);let o=resolve(e,`functions`),s=resolve(o,`${a}.func`);if(!s.startsWith(`${o}${sep}`))throw Error(`Vercel middlewarePath escapes the functions directory: ${t}.`);return s}async function copyHostMiddlewareFunctions(n){let r;try{r=await readFile(join(n.hostOutputDirectory,`config.json`),`utf8`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}let i=JSON.parse(r);if(!isRecord(i))return;let c=new Set;if(Array.isArray(i.routes))for(let e of i.routes)isRecord(e)&&typeof e.middlewarePath==`string`&&c.add(e.middlewarePath);let l=resolveMiddlewareFunctionDirectory(n.hostOutputDirectory,NEXT_MIDDLEWARE_PATH);try{await access(l),c.add(NEXT_MIDDLEWARE_PATH)}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}for(let t of c){let r=resolveMiddlewareFunctionDirectory(n.hostOutputDirectory,t),i=resolveMiddlewareFunctionDirectory(n.serviceOutputDirectory,t);await mkdir(dirname(i),{recursive:!0}),await cp(r,i,{force:!0,recursive:!0})}}export{copyHostMiddlewareFunctions};
|
|
@@ -28,8 +28,9 @@ export interface HttpBasicCredentials {
|
|
|
28
28
|
* Verifies an HTTP Basic credential against the supplied username and
|
|
29
29
|
* password. Returns `{ ok: true, sessionAuth }` on success or `{ ok: false }`
|
|
30
30
|
* on a missing or mismatched credential. The password is compared with
|
|
31
|
-
* constant-time hash equality so a timing side channel cannot leak it
|
|
32
|
-
*
|
|
31
|
+
* constant-time hash equality so a timing side channel cannot leak it. Both
|
|
32
|
+
* values are normalized to Unicode NFC before comparison, matching the
|
|
33
|
+
* `charset="UTF-8"` challenge advertised by {@link httpBasic}.
|
|
33
34
|
*/
|
|
34
35
|
export declare function verifyHttpBasic(authorizationHeader: string | null, credentials: HttpBasicCredentials): VerifyResult;
|
|
35
36
|
/**
|
|
@@ -229,11 +230,33 @@ export declare class ForbiddenError extends Error {
|
|
|
229
230
|
* traffic, include {@link none} as the final entry.
|
|
230
231
|
*/
|
|
231
232
|
export type AuthFn<TEvent = Request> = (event: TEvent) => SessionAuthContext | null | undefined | Promise<SessionAuthContext | null | undefined>;
|
|
233
|
+
/**
|
|
234
|
+
* Attaches declared `www-authenticate` challenges to an {@link AuthFn}
|
|
235
|
+
* without changing its call signature or behavior. {@link routeAuth} reads
|
|
236
|
+
* the declared challenges back when every entry in the walk skips, so the
|
|
237
|
+
* resulting 401 advertises the scheme(s) the configured strategies actually
|
|
238
|
+
* accept (e.g. `Basic` for {@link httpBasic}) instead of a fixed default.
|
|
239
|
+
*
|
|
240
|
+
* Built-in strategies (`httpBasic`, `jwtHmac`, `jwtEcdsa`, `oidc`,
|
|
241
|
+
* `vercelOidc`) already declare their challenge. Use this directly when
|
|
242
|
+
* authoring a custom `AuthFn`:
|
|
243
|
+
*
|
|
244
|
+
* ```ts
|
|
245
|
+
* const apiKey = withAuthChallenges(
|
|
246
|
+
* (request) => (isValidApiKey(request) ? sessionAuth : null),
|
|
247
|
+
* [{ scheme: "Bearer" }],
|
|
248
|
+
* );
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export declare function withAuthChallenges<TEvent>(fn: AuthFn<TEvent>, challenges: readonly UnauthorizedChallenge[]): AuthFn<TEvent>;
|
|
232
252
|
/**
|
|
233
253
|
* Walks an `AuthFn` (or array) in order against `request`. The first entry
|
|
234
254
|
* returning a {@link SessionAuthContext} wins; entries returning `null` or
|
|
235
255
|
* `undefined` are skipped. If the walk exhausts without a winner (including
|
|
236
|
-
* the empty-array case), returns a 401 {@link createUnauthorizedResponse}
|
|
256
|
+
* the empty-array case), returns a 401 {@link createUnauthorizedResponse}
|
|
257
|
+
* whose `www-authenticate` challenges are collected from the entries'
|
|
258
|
+
* declared schemes (see {@link withAuthChallenges}), falling back to
|
|
259
|
+
* `Bearer` when none declared any.
|
|
237
260
|
*
|
|
238
261
|
* Channel factories that share this resolution policy (e.g. `eveChannel`, or
|
|
239
262
|
* a custom `defineChannel` route handler) should call `routeAuth` rather than
|
|
@@ -411,19 +434,46 @@ export declare function vercelSubject(input: VercelSubjectInput): string;
|
|
|
411
434
|
/**
|
|
412
435
|
* Returns an HTTP route auth callback backed by Vercel OIDC. See
|
|
413
436
|
* {@link verifyVercelOidc} for the always-on current-project bypass and how
|
|
414
|
-
* `subjects` extends acceptance to other Vercel projects.
|
|
437
|
+
* `subjects` extends acceptance to other Vercel projects. Declares a
|
|
438
|
+
* `Bearer` {@link withAuthChallenges} challenge for {@link routeAuth}'s 401.
|
|
415
439
|
*/
|
|
416
440
|
export declare function vercelOidc(opts?: VerifyVercelOidcOptions): AuthFn<Request>;
|
|
417
|
-
/**
|
|
418
|
-
|
|
419
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Options accepted by {@link httpBasic}.
|
|
443
|
+
*/
|
|
444
|
+
export interface HttpBasicAuthOptions {
|
|
445
|
+
/**
|
|
446
|
+
* Optional `realm` parameter advertised on the `WWW-Authenticate: Basic`
|
|
447
|
+
* challenge (e.g. browsers show it in the native login prompt). Defaults
|
|
448
|
+
* to `"eve"`.
|
|
449
|
+
*/
|
|
450
|
+
readonly realm?: string;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Returns an {@link AuthFn} that verifies HTTP Basic credentials via
|
|
454
|
+
* {@link verifyHttpBasic}. Declares a `Basic` {@link withAuthChallenges}
|
|
455
|
+
* challenge so a {@link routeAuth} 401 advertises `WWW-Authenticate: Basic`
|
|
456
|
+
* (with `realm` first, when given, then `charset="UTF-8"`) instead of the
|
|
457
|
+
* `Bearer` fallback.
|
|
458
|
+
*/
|
|
459
|
+
export declare function httpBasic(credentials: HttpBasicCredentials, options?: HttpBasicAuthOptions): AuthFn<Request>;
|
|
460
|
+
/**
|
|
461
|
+
* Returns an {@link AuthFn} that verifies an HMAC-signed bearer JWT via
|
|
462
|
+
* {@link verifyJwtHmac}. Declares a `Bearer` {@link withAuthChallenges}
|
|
463
|
+
* challenge for {@link routeAuth}'s 401.
|
|
464
|
+
*/
|
|
420
465
|
export declare function jwtHmac(config: VerifyJwtHmacConfig): AuthFn<Request>;
|
|
421
|
-
/**
|
|
466
|
+
/**
|
|
467
|
+
* Returns an {@link AuthFn} that verifies an ECDSA-signed bearer JWT via
|
|
468
|
+
* {@link verifyJwtEcdsa}. Declares a `Bearer` {@link withAuthChallenges}
|
|
469
|
+
* challenge for {@link routeAuth}'s 401.
|
|
470
|
+
*/
|
|
422
471
|
export declare function jwtEcdsa(config: VerifyJwtEcdsaConfig): AuthFn<Request>;
|
|
423
472
|
/**
|
|
424
473
|
* Returns an {@link AuthFn} that verifies an OIDC bearer token on the inbound
|
|
425
474
|
* request via {@link verifyOidc}. Use {@link vercelOidc} instead for
|
|
426
475
|
* Vercel-issued tokens: it preconfigures the issuer, audience, and runtime
|
|
427
|
-
* principal flag.
|
|
476
|
+
* principal flag. Declares a `Bearer` {@link withAuthChallenges} challenge
|
|
477
|
+
* for {@link routeAuth}'s 401.
|
|
428
478
|
*/
|
|
429
479
|
export declare function oidc(config: VerifyOidcConfig): AuthFn<Request>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{resolveVercelOidcCurrentProject}from"#runtime/governance/auth/vercel-oidc-project.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";const vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let n=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1,currentVercelProject:void 0});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){if(e===null||e.length===0)return{kind:`not-authenticated`};let n={acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}};return await authenticateOidcStrategy({strategy:t.currentVercelProject===void 0?n:{...n,currentVercelProject:t.currentVercelProject},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}var UnauthenticatedError=class extends Error{response;constructor(e={}){super(e.message??`Authorization is required for this route.`),this.name=`UnauthenticatedError`,this.response=createUnauthorizedResponse({...e,status:401})}},ForbiddenError=class extends Error{response;constructor(e={}){super(e.message??`Forbidden.`),this.name=`ForbiddenError`,this.response=createUnauthorizedResponse({...e,status:403})}};async function routeAuth(e,t){let n=Array.isArray(t)?t:[t];try{for(let t of n){let n=await t(e);if(n)return n}}catch(e){if(typeof e==`object`&&e&&`response`in e&&e.response instanceof Response)return e.response;throw e}return createUnauthorizedResponse({challenges:[{scheme:`Bearer`}]})}function placeholderAuth(){return()=>{if(process.env.VERCEL_ENV!==`production`)return null;throw new UnauthenticatedError({code:`eve_production_auth_not_configured`,message:`Production auth is not configured. Replace placeholderAuth() in agent/channels/eve.ts with your app's auth provider.`})}}function none(){return()=>ANONYMOUS_SESSION_AUTH_CONTEXT}function localDev(){return e=>process.env.VERCEL&&process.env.VERCEL_ENV===`development`||isLoopbackRequest(e)?LOCAL_DEV_SESSION_AUTH_CONTEXT:null}const LOOPBACK_HOSTNAMES=new Set([`localhost`,`[::1]`]),LOOPBACK_IPV4_PREFIX=/^127\./;function isLoopbackRequest(e){let t;try{t=new URL(e.url).hostname}catch{return!1}return!!(LOOPBACK_HOSTNAMES.has(t)||LOOPBACK_IPV4_PREFIX.test(t)||t.endsWith(`.localhost`))}const ANONYMOUS_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`none`,principalId:`anonymous`,principalType:`anonymous`},LOCAL_DEV_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`local-dev`,principalId:`local-dev`,principalType:`local-dev`};async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(`https://oidc.vercel.com/`))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};if(!n.audiences.some(e=>e.startsWith(`https://vercel.com/`)))return vercelOidcLog.debug(`Rejected token whose audience is not a Vercel audience.`,{audiences:n.audiences,issuer:n.issuer}),{ok:!1};let r=resolveCurrentVercelProject(t),i=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,currentVercelProject:r,issuer:n.issuer,subjects:t.subjects??[]});return i.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:i.principal.principalType,subject:i.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(i.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:i.kind,subjectsConfigured:(t.subjects??[]).length>0,...i.kind===`misconfigured`?{detail:i.message}:{}}),{ok:!1})}function resolveCurrentVercelProject(e){if(e.currentVercelProject!==void 0)return e.currentVercelProject;let t=process.env.VERCEL_PROJECT_ID?.trim();if(t===void 0||t.length===0)return;let n=process.env.VERCEL_TARGET_ENV?.trim()||process.env.VERCEL_ENV?.trim();return n===void 0||n.length===0?{projectId:t}:{environment:n,projectId:t}}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return async n=>{let r=extractBearerToken(n.headers.get(`authorization`)),i=e.currentVercelProject??(r!==null&&isLocalDevelopmentVercelOidcRequest(n)?await resolveVercelOidcCurrentProject(n):void 0),a=await verifyVercelOidc(r,i===void 0?e:{...e,currentVercelProject:i});return a.ok?a.sessionAuth:null}}function isLocalDevelopmentVercelOidcRequest(e){return process.env.VERCEL_ENV===`development`?!0:process.env.VERCEL_ENV===`preview`||process.env.VERCEL_ENV===`production`?!1:isLoopbackRequest(e)}function httpBasic(e){return t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null}}function jwtHmac(e){return async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function jwtEcdsa(e){return async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function oidc(e){return async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function decodeUnverifiedJwtClaims(e){let t;try{t=decodeJwt(e)}catch{return null}return typeof t.iss!=`string`||t.iss.length===0?null:{audiences:typeof t.aud==`string`?[t.aud]:Array.isArray(t.aud)?t.aud.filter(e=>typeof e==`string`):[],issuer:t.iss}}export{ForbiddenError,UnauthenticatedError,createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,isLoopbackRequest,jwtEcdsa,jwtHmac,localDev,none,oidc,placeholderAuth,routeAuth,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc};
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{resolveVercelOidcCurrentProject}from"#runtime/governance/auth/vercel-oidc-project.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";const vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let n=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1,currentVercelProject:void 0});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){if(e===null||e.length===0)return{kind:`not-authenticated`};let n={acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}};return await authenticateOidcStrategy({strategy:t.currentVercelProject===void 0?n:{...n,currentVercelProject:t.currentVercelProject},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}var UnauthenticatedError=class extends Error{response;constructor(e={}){super(e.message??`Authorization is required for this route.`),this.name=`UnauthenticatedError`,this.response=createUnauthorizedResponse({...e,status:401})}},ForbiddenError=class extends Error{response;constructor(e={}){super(e.message??`Forbidden.`),this.name=`ForbiddenError`,this.response=createUnauthorizedResponse({...e,status:403})}};const AUTH_CHALLENGES_SYMBOL=Symbol.for(`eve.channels.auth.challenges`);function withAuthChallenges(e,t){let wrapped=t=>e(t);return Object.defineProperty(wrapped,AUTH_CHALLENGES_SYMBOL,{value:t}),wrapped}function getDeclaredChallenges(e){return e[AUTH_CHALLENGES_SYMBOL]}function collectDeclaredChallenges(e){let t=new Set,n=[];for(let r of e)for(let e of getDeclaredChallenges(r)??[]){let r=formatChallenge(e);t.has(r)||(t.add(r),n.push(e))}return n}async function routeAuth(e,t){let n=Array.isArray(t)?t:[t];try{for(let t of n){let n=await t(e);if(n)return n}}catch(e){if(typeof e==`object`&&e&&`response`in e&&e.response instanceof Response)return e.response;throw e}let r=collectDeclaredChallenges(n);return createUnauthorizedResponse({challenges:r.length>0?r:[{scheme:`Bearer`}]})}function placeholderAuth(){return()=>{if(process.env.VERCEL_ENV!==`production`)return null;throw new UnauthenticatedError({code:`eve_production_auth_not_configured`,message:`Production auth is not configured. Replace placeholderAuth() in agent/channels/eve.ts with your app's auth provider.`})}}function none(){return()=>ANONYMOUS_SESSION_AUTH_CONTEXT}function localDev(){return e=>process.env.VERCEL&&process.env.VERCEL_ENV===`development`||isLoopbackRequest(e)?LOCAL_DEV_SESSION_AUTH_CONTEXT:null}const LOOPBACK_HOSTNAMES=new Set([`localhost`,`[::1]`]),LOOPBACK_IPV4_PREFIX=/^127\./;function isLoopbackRequest(e){let t;try{t=new URL(e.url).hostname}catch{return!1}return!!(LOOPBACK_HOSTNAMES.has(t)||LOOPBACK_IPV4_PREFIX.test(t)||t.endsWith(`.localhost`))}const ANONYMOUS_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`none`,principalId:`anonymous`,principalType:`anonymous`},LOCAL_DEV_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`local-dev`,principalId:`local-dev`,principalType:`local-dev`};async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(`https://oidc.vercel.com/`))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};if(!n.audiences.some(e=>e.startsWith(`https://vercel.com/`)))return vercelOidcLog.debug(`Rejected token whose audience is not a Vercel audience.`,{audiences:n.audiences,issuer:n.issuer}),{ok:!1};let r=resolveCurrentVercelProject(t),i=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,currentVercelProject:r,issuer:n.issuer,subjects:t.subjects??[]});return i.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:i.principal.principalType,subject:i.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(i.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:i.kind,subjectsConfigured:(t.subjects??[]).length>0,...i.kind===`misconfigured`?{detail:i.message}:{}}),{ok:!1})}function resolveCurrentVercelProject(e){if(e.currentVercelProject!==void 0)return e.currentVercelProject;let t=process.env.VERCEL_PROJECT_ID?.trim();if(t===void 0||t.length===0)return;let n=process.env.VERCEL_TARGET_ENV?.trim()||process.env.VERCEL_ENV?.trim();return n===void 0||n.length===0?{projectId:t}:{environment:n,projectId:t}}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return withAuthChallenges(async n=>{let r=extractBearerToken(n.headers.get(`authorization`)),i=e.currentVercelProject??(r!==null&&isLocalDevelopmentVercelOidcRequest(n)?await resolveVercelOidcCurrentProject(n):void 0),a=await verifyVercelOidc(r,i===void 0?e:{...e,currentVercelProject:i});return a.ok?a.sessionAuth:null},[{scheme:`Bearer`}])}function isLocalDevelopmentVercelOidcRequest(e){return process.env.VERCEL_ENV===`development`?!0:process.env.VERCEL_ENV===`preview`||process.env.VERCEL_ENV===`production`?!1:isLoopbackRequest(e)}function httpBasic(e,t){return withAuthChallenges(t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null},[{parameters:{realm:t?.realm??`eve`,charset:`UTF-8`},scheme:`Basic`}])}function jwtHmac(e){return withAuthChallenges(async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null},[{scheme:`Bearer`}])}function jwtEcdsa(e){return withAuthChallenges(async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null},[{scheme:`Bearer`}])}function oidc(e){return withAuthChallenges(async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null},[{scheme:`Bearer`}])}function decodeUnverifiedJwtClaims(e){let t;try{t=decodeJwt(e)}catch{return null}return typeof t.iss!=`string`||t.iss.length===0?null:{audiences:typeof t.aud==`string`?[t.aud]:Array.isArray(t.aud)?t.aud.filter(e=>typeof e==`string`):[],issuer:t.iss}}export{ForbiddenError,UnauthenticatedError,createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,isLoopbackRequest,jwtEcdsa,jwtHmac,localDev,none,oidc,placeholderAuth,routeAuth,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc,withAuthChallenges};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveEveDestinationPrefix}from"./server.js";import{ensureEveVercelOutputConfig}from"./vercel-output-config.js";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{isAbsolute,relative,resolve}from"node:path";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const EVE_NEXT_SERVICE_PREFIX=`/_eve_internal/eve`,EVE_NEXT_PRODUCTION_PORT_ENV=`EVE_NEXT_PRODUCTION_PORT`,AGENT_NAME_PATTERN=/^[a-z0-9][a-z0-9_-]*$/;function resolveApplicationRoot(e){return e===void 0||e.length===0?process.cwd():isAbsolute(e)?e:resolve(process.cwd(),e)}function resolveDevServerTimeout(e){if(e!==void 0){if(!Number.isFinite(e)||e<=0)throw Error(`eve Next.js development server timeout must be a positive number.`);return e}}function normalizeRoutePrefix(e){let t=(e.startsWith(`/`)?e:`/${e}`).replace(/\/+$/,``);if(t.length===0)throw Error(`eve Next.js service prefix cannot resolve to the root route.`);return t}function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function createNamedAgentRoutePrefix(e){return joinRoutePrefix(`/eve/agents`,e)}function createNamedAgentServicePrefix(e,t){return joinRoutePrefix(e,t)}function createAgentRewriteSource(e){return joinRoutePrefix(e,`${EVE_ROUTE_PREFIX}/:path+`)}function normalizeOrigin(e){return new URL(e.trim()).origin}function readLocalProductionPort(e){let t=process.env[EVE_NEXT_PRODUCTION_PORT_ENV],n=t===void 0||t.trim().length===0?4274:Number.parseInt(t,10);if(t!==void 0&&t.trim().length>0&&String(n)!==t.trim())throw Error(`${EVE_NEXT_PRODUCTION_PORT_ENV} must be an integer between 1 and 65535.`);let r=n+e;if(r<1||r>65535)throw Error(`${EVE_NEXT_PRODUCTION_PORT_ENV} plus the eve agent count exceeds 65535.`);return r}function resolveProductionDestination(e){if(process.env.VERCEL)return{destinationPrefix:e.servicePrefix};let t=process.env.EVE_NEXT_PRODUCTION_ORIGIN;if(t!==void 0&&t.trim().length>0)return{destinationPrefix:joinRoutePrefix(normalizeOrigin(t),e.servicePrefix)};let n=`http://127.0.0.1:${String(readLocalProductionPort(e.localProductionPortOffset))}`;return{destinationPrefix:n,localServerOrigin:n}}function createEveRewriteRule(e){let t=createAgentRewriteSource(e.publicRoutePrefix);return{destination:joinRoutePrefix(e.destinationPrefix,`${EVE_ROUTE_PREFIX}/:path+`),source:t}}async function resolveExistingRewrites(e){return await e?.()}function mergeRewriteRules(e,t){return e===void 0?{beforeFiles:t}:isRewriteSections(e)?{...e,beforeFiles:[...t,...e.beforeFiles??[]]}:{afterFiles:e,beforeFiles:t}}function isRewriteSections(e){return!Array.isArray(e)}async function resolveNextConfig(e,t,n){return typeof e==`function`?await e(t,n):e}function assertValidAgentName(e){if(!AGENT_NAME_PATTERN.test(e))throw Error(`eve Next.js agent name ${JSON.stringify(e)} is invalid. Use lowercase letters, numbers, underscores, or hyphens, starting with a letter or number.`)}function quoteShellArg(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function toPosixPath(e){return e.replaceAll(`\\`,`/`)}function createDefaultBuildCommand(e){return`node ${quoteShellArg(toPosixPath(relative(e.agentRoot,resolveEveBinaryPath(e.nextRoot))))} build`}function normalizeAgentsConfig(e,t){let n=normalizeRoutePrefix(e.servicePrefix??`/_eve_internal/eve`),resolveBuildCommand=(n,r)=>r??e.eveBuildCommand??createDefaultBuildCommand({agentRoot:n,nextRoot:t});if(e.agents===void 0){let t=resolveApplicationRoot(e.eveRoot);return[{appRoot:t,buildCommand:resolveBuildCommand(t,void 0),localProductionPortOffset:0,publicRoutePrefix:``,servicePrefix:n}]}if(e.eveRoot!==void 0)throw Error(`withEve cannot combine eveRoot with agents. Use one configuration form.`);let r=Object.entries(e.agents);if(r.length===0)throw Error(`withEve agents must contain at least one named eve agent.`);return r.map(([e,t],r)=>{assertValidAgentName(e);let i=typeof t==`string`?{root:t}:t,a=resolveApplicationRoot(i.root);return{appRoot:a,buildCommand:resolveBuildCommand(a,i.buildCommand),localProductionPortOffset:r,name:e,publicRoutePrefix:createNamedAgentRoutePrefix(e),servicePrefix:normalizeRoutePrefix(i.servicePrefix??createNamedAgentServicePrefix(n,e))}})}function withEve(n,r={}){let i=process.cwd(),a=resolveDevServerTimeout(r.devServerTimeoutMs),o=normalizeAgentsConfig(r,i);return async function(r,s){let c=await resolveNextConfig(n,r,s),l=c.rewrites,u=await ensureEveVercelOutputConfig({agents:o.map(e=>({appRoot:e.appRoot,buildCommand:e.buildCommand,name:e.name,publicRoutePrefix:e.publicRoutePrefix,servicePrefix:e.servicePrefix})),nextRoot:i});if(process.env.VERCEL)return c;let d=new Map(u.agents.map(e=>[e.name,e])),f=o.map(e=>{let t=d.get(e.name),n=resolveProductionDestination({localProductionPortOffset:e.localProductionPortOffset,servicePrefix:t?.servicePrefix??e.servicePrefix});return{...e,productionDestination:n}});return{...c,async rewrites(){let[t,n]=await Promise.all([resolveExistingRewrites(l),Promise.all(f.map(async t=>createEveRewriteRule({destinationPrefix:await resolveEveDestinationPrefix({appRoot:t.appRoot,devServerTimeoutMs:a,logLabel:t.name,phase:r,productionDestinationPrefix:t.productionDestination.destinationPrefix,productionServerOrigin:t.productionDestination.localServerOrigin}),publicRoutePrefix:t.publicRoutePrefix})))]);return mergeRewriteRules(t,n)}}}}export{EVE_NEXT_SERVICE_PREFIX,withEve};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default,
|
|
1
|
+
export { default, type EveNuxtModuleOptions } from "./module.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import module_default from"./module.js";export{module_default as default};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { EVE_NUXT_SERVICE_PREFIX } from "./routing.js";
|
|
2
|
-
export { EVE_NUXT_SERVICE_PREFIX };
|
|
3
1
|
/**
|
|
4
2
|
* Options for the eve Nuxt module.
|
|
5
3
|
*/
|
|
@@ -7,37 +5,25 @@ export interface EveNuxtModuleOptions {
|
|
|
7
5
|
/**
|
|
8
6
|
* Path to the eve application root, resolved relative to the Nuxt project
|
|
9
7
|
* root unless absolute. Defaults to the Nuxt project root. The dev server is
|
|
10
|
-
* spawned here and
|
|
11
|
-
*
|
|
8
|
+
* spawned here, and on Vercel it is the root the generated eve service
|
|
9
|
+
* builds from.
|
|
12
10
|
*/
|
|
13
11
|
eveRoot?: string;
|
|
14
12
|
/**
|
|
15
|
-
*
|
|
13
|
+
* Command that builds the eve app inside the generated Vercel eve service.
|
|
14
|
+
* Defaults to running the installed eve binary from the Nuxt app's
|
|
15
|
+
* dependencies (`node <path-to>/eve/bin/eve.js build`).
|
|
16
16
|
*/
|
|
17
17
|
eveBuildCommand?: string;
|
|
18
|
-
/**
|
|
19
|
-
* Set to `false` to skip creating or updating `vercel.json`. By default the
|
|
20
|
-
* module ensures `vercel.json` contains `experimentalServices` for the Nuxt
|
|
21
|
-
* app and eve app.
|
|
22
|
-
*/
|
|
23
|
-
configureVercelJson?: boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Private Vercel service prefix eve transport is proxied to. Defaults to
|
|
26
|
-
* {@link EVE_NUXT_SERVICE_PREFIX}. When `configureVercelJson` is enabled, it
|
|
27
|
-
* is written as the eve service `routePrefix`, but an existing `routePrefix`
|
|
28
|
-
* in `vercel.json` takes precedence. Normalized to a leading-slash,
|
|
29
|
-
* no-trailing-slash route; cannot resolve to `/`.
|
|
30
|
-
*/
|
|
31
|
-
servicePrefix?: string;
|
|
32
18
|
}
|
|
33
19
|
/**
|
|
34
20
|
* Nuxt module that wires an eve agent into a Nuxt app. Register under `modules`
|
|
35
21
|
* (configured via the `eve` config key). It auto-imports the `useEveAgent()`
|
|
36
|
-
* composable
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
22
|
+
* composable and routes eve transport requests (`/eve/v1/**`) to the eve
|
|
23
|
+
* service: a shared dev server spawned on demand in dev, a generated Vercel
|
|
24
|
+
* service on Vercel deployments, and a configured origin/port in non-Vercel
|
|
25
|
+
* production. Requires Nuxt >= 4.0.0. Configure via
|
|
26
|
+
* {@link EveNuxtModuleOptions}.
|
|
41
27
|
*/
|
|
42
28
|
declare const _default: import("nuxt/schema").NuxtModule<EveNuxtModuleOptions, EveNuxtModuleOptions, false>;
|
|
43
29
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{joinRoutePrefix,normalizeOrigin,resolveProductionTarget}from"./routing.js";import{EVE_BASE_URL_ENV,resolveSharedEveDevServer}from"./dev-server.js";import{ensureEveVercelServicesConfig,mergeEveVercelConfig}from"./vercel-services.js";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{isAbsolute,resolve}from"node:path";import{addImports,defineNuxtModule,extendRouteRules}from"@nuxt/kit";function resolveApplicationRoot(e,t){return t===void 0||t.length===0?e:isAbsolute(t)?t:resolve(e,t)}async function resolveEveProxyTarget(a){if(!a.dev)return resolveProductionTarget();let o=process.env[EVE_BASE_URL_ENV]?.trim();if(o&&o.length>0)return joinRoutePrefix(normalizeOrigin(o),EVE_ROUTE_PREFIX);let s=await resolveSharedEveDevServer(a.appRoot);return s.process!==void 0&&a.onDevServerSpawned?.(s.process),joinRoutePrefix(s.origin,EVE_ROUTE_PREFIX)}var module_default=defineNuxtModule({meta:{name:`eve`,configKey:`eve`,compatibility:{nuxt:`>=4.0.0`}},defaults:{},async setup(e,t){let n=t.options.rootDir,r=resolveApplicationRoot(n,e.eveRoot);if(addImports({name:`useEveAgent`,from:`eve/vue`}),!t.options.dev&&process.env.VERCEL){let i=await ensureEveVercelServicesConfig({appRoot:r,eveBuildCommand:e.eveBuildCommand,nuxtRoot:n});if(i.mode===`generated`){let e=t.options.nitro;e.vercel={...e.vercel,config:mergeEveVercelConfig(e.vercel?.config,i)}}}else t.hook(`modules:done`,async()=>{let e=await resolveEveProxyTarget({appRoot:r,dev:t.options.dev,onDevServerSpawned:e=>{t.hook(`close`,()=>{e.killed||e.kill()})}});extendRouteRules(`${EVE_ROUTE_PREFIX}/**`,{proxy:`${e}/**`})})}});export{module_default as default};
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Private route namespace used when a Vercel deployment hosts eve as a
|
|
3
|
-
* separate experimental service behind the Nuxt app.
|
|
4
|
-
*/
|
|
5
|
-
export declare const EVE_NUXT_SERVICE_PREFIX = "/_eve_internal/eve";
|
|
6
|
-
/**
|
|
7
|
-
* Normalize a user-supplied service prefix into a leading-slash, no-trailing-
|
|
8
|
-
* slash route. Throws when the prefix resolves to the root route, which would
|
|
9
|
-
* collide with the Nuxt web service.
|
|
10
|
-
*/
|
|
11
|
-
export declare function normalizeRoutePrefix(prefix: string): string;
|
|
12
1
|
/**
|
|
13
2
|
* Join a route prefix and a path with exactly one separating slash.
|
|
14
3
|
*/
|
|
@@ -24,32 +13,9 @@ export declare function normalizeOrigin(origin: string): string;
|
|
|
24
13
|
*/
|
|
25
14
|
export declare function readLocalProductionPort(): number;
|
|
26
15
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly dest: string;
|
|
32
|
-
/**
|
|
33
|
-
* Re-run route matching against the rewritten `dest`. Required so the
|
|
34
|
-
* rewritten eve service path is routed to the sibling eve service instead of
|
|
35
|
-
* being resolved inside the host service's own filesystem (which 404s).
|
|
36
|
-
*/
|
|
37
|
-
readonly check: true;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Build the edge-level Vercel rewrite that forwards eve transport requests
|
|
41
|
-
* (`/eve/v1/**`) to the eve service prefix (`/_eve_internal/eve/eve/v1/**`).
|
|
42
|
-
*
|
|
43
|
-
* Mirrors the Next.js integration's `beforeFiles` rewrite. A Nitro runtime
|
|
44
|
-
* `proxy` route rule cannot reach a sibling Vercel service — the proxied
|
|
45
|
-
* request loops back into the Nuxt function and 404s — so production routing
|
|
46
|
-
* must happen at the edge via the build output config instead.
|
|
47
|
-
*/
|
|
48
|
-
export declare function createEveVercelRewriteRoute(servicePrefix: string): EveVercelRewriteRoute;
|
|
49
|
-
/**
|
|
50
|
-
* Resolve the proxy destination for eve routes in production.
|
|
51
|
-
*
|
|
52
|
-
* On Vercel the destination is the private service prefix. Off Vercel it is an
|
|
53
|
-
* explicit origin override (`EVE_NUXT_PRODUCTION_ORIGIN`) or a local port.
|
|
16
|
+
* Resolve the proxy destination for eve routes in non-Vercel production: an
|
|
17
|
+
* explicit origin override (`EVE_NUXT_PRODUCTION_ORIGIN`) or a local port. On
|
|
18
|
+
* Vercel the module routes at the edge via a Build Output service route
|
|
19
|
+
* instead of proxying.
|
|
54
20
|
*/
|
|
55
|
-
export declare function resolveProductionTarget(
|
|
21
|
+
export declare function resolveProductionTarget(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";const
|
|
1
|
+
import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";const EVE_NUXT_PRODUCTION_PORT_ENV=`EVE_NUXT_PRODUCTION_PORT`;function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e.trim()).origin}function readLocalProductionPort(){let e=process.env[EVE_NUXT_PRODUCTION_PORT_ENV];if(e===void 0||e.trim().length===0)return 4274;let n=Number.parseInt(e,10);if(String(n)!==e.trim()||n<1||n>65535)throw Error(`${EVE_NUXT_PRODUCTION_PORT_ENV} must be an integer between 1 and 65535.`);return n}function resolveProductionTarget(){let t=process.env.EVE_NUXT_PRODUCTION_ORIGIN;return t!==void 0&&t.trim().length>0?joinRoutePrefix(normalizeOrigin(t),EVE_ROUTE_PREFIX):joinRoutePrefix(`http://127.0.0.1:${String(readLocalProductionPort())}`,EVE_ROUTE_PREFIX)}export{joinRoutePrefix,normalizeOrigin,readLocalProductionPort,resolveProductionTarget};
|