@gmickel/gno 1.27.1 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -20
- package/assets/skill/SKILL.md +59 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +2 -2
- package/spec/cli.md +82 -5
- package/spec/db/schema.sql +31 -0
- package/spec/mcp.md +71 -0
- package/spec/output-schemas/ask.schema.json +156 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +183 -3
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/get.schema.json +94 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/mcp-job-status.schema.json +28 -0
- package/spec/output-schemas/multi-get.schema.json +128 -0
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +223 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-result.schema.json +94 -0
- package/spec/output-schemas/search-results.schema.json +155 -0
- package/spec/project-profile.schema.json +66 -0
- package/src/app/context-format.ts +1 -1
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/get.ts +12 -2
- package/src/cli/commands/index-cmd.ts +13 -0
- package/src/cli/commands/multi-get.ts +9 -2
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/shared.ts +28 -0
- package/src/cli/commands/update.ts +5 -0
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +127 -0
- package/src/config/index.ts +9 -0
- package/src/config/project-profile.ts +2 -0
- package/src/config/types.ts +66 -0
- package/src/converters/adapters/browser-export/adapter.ts +199 -0
- package/src/converters/adapters/browser-export/formats.ts +358 -0
- package/src/converters/adapters/email/adapter.ts +429 -0
- package/src/converters/adapters/email/html.ts +162 -0
- package/src/converters/adapters/email/mime.ts +454 -0
- package/src/converters/adapters/email/parameters.ts +77 -0
- package/src/converters/adapters/ical/adapter.ts +475 -0
- package/src/converters/adapters/ical/recurrence.ts +186 -0
- package/src/converters/adapters/jsonl/adapter.ts +238 -0
- package/src/converters/adapters/jsonl/config.ts +105 -0
- package/src/converters/adapters/shared/html-text.ts +165 -0
- package/src/converters/adapters/shared/record-utils.ts +79 -0
- package/src/converters/adapters/shared/utf8-lines.ts +141 -0
- package/src/converters/adapters/transcript/adapter.ts +295 -0
- package/src/converters/adapters/transcript/json.ts +184 -0
- package/src/converters/adapters/transcript/model.ts +171 -0
- package/src/converters/adapters/transcript/text.ts +58 -0
- package/src/converters/adapters/transcript/timed.ts +152 -0
- package/src/converters/index.ts +11 -1
- package/src/converters/mime.ts +8 -0
- package/src/converters/pipeline.ts +15 -1
- package/src/converters/registry.ts +37 -1
- package/src/converters/types.ts +136 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +198 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -112
- package/src/core/context-evidence.ts +93 -15
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/document-capabilities.ts +12 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/project-profile-apply-state.ts +5 -0
- package/src/core/project-profile.ts +4 -0
- package/src/core/record-metadata.ts +49 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter-canonical.ts +433 -0
- package/src/ingestion/record-adapter.ts +448 -0
- package/src/ingestion/record-container.ts +704 -0
- package/src/ingestion/record-path.ts +20 -0
- package/src/ingestion/record-sync.ts +70 -0
- package/src/ingestion/sync.ts +243 -36
- package/src/ingestion/types.ts +71 -1
- package/src/ingestion/walker.ts +31 -11
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/get.ts +10 -2
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/multi-get.ts +9 -2
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/mcp/tools/workspace-write.ts +2 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/filters.ts +1 -1
- package/src/pipeline/graph-retrieval.ts +7 -4
- package/src/pipeline/hybrid.ts +21 -4
- package/src/pipeline/result-context.ts +12 -4
- package/src/pipeline/search.ts +23 -4
- package/src/pipeline/types.ts +6 -0
- package/src/pipeline/vsearch.ts +67 -28
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/documents.ts +13 -5
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/browse-tree.ts +4 -2
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +237 -65
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/022-record-export-lineage.ts +42 -0
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +8 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +284 -14
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +166 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
package/src/ingestion/walker.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type { SkippedEntry, WalkConfig, WalkEntry, WalkerPort } from "./types";
|
|
|
21
21
|
|
|
22
22
|
import { SUPPORTED_EXTENSIONS } from "../converters/mime";
|
|
23
23
|
import { matchesCollectionExclusion } from "../core/path-rules";
|
|
24
|
+
import { isRecordVirtualPath } from "./record-path";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Regex to detect dangerous patterns with parent directory traversal.
|
|
@@ -124,7 +125,7 @@ function scanPatterns(pattern: string): string[] {
|
|
|
124
125
|
async function safeRelPath(
|
|
125
126
|
rootReal: string,
|
|
126
127
|
absPath: string
|
|
127
|
-
): Promise<string | null> {
|
|
128
|
+
): Promise<{ absPath: string; relPath: string } | null> {
|
|
128
129
|
try {
|
|
129
130
|
const fileReal = await realpath(absPath);
|
|
130
131
|
const rel = relative(rootReal, fileReal);
|
|
@@ -135,7 +136,7 @@ async function safeRelPath(
|
|
|
135
136
|
return null;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
return toPosixPath(rel);
|
|
139
|
+
return { absPath: fileReal, relPath: toPosixPath(rel) };
|
|
139
140
|
} catch {
|
|
140
141
|
// Can't resolve path (e.g., broken symlink)
|
|
141
142
|
return null;
|
|
@@ -145,18 +146,25 @@ async function safeRelPath(
|
|
|
145
146
|
/**
|
|
146
147
|
* Check if a file extension matches the include list.
|
|
147
148
|
* Include list contains extensions like ".md" or "md" (normalized).
|
|
148
|
-
* When include is empty, falls back to SUPPORTED_EXTENSIONS
|
|
149
|
-
*
|
|
149
|
+
* When include is empty, falls back to SUPPORTED_EXTENSIONS plus extensions
|
|
150
|
+
* made convertible by explicit adapter configuration.
|
|
150
151
|
*/
|
|
151
|
-
function matchesInclude(
|
|
152
|
+
function matchesInclude(
|
|
153
|
+
relPath: string,
|
|
154
|
+
include: string[],
|
|
155
|
+
additionalDefaultExtensions: string[]
|
|
156
|
+
): boolean {
|
|
152
157
|
const ext = extname(relPath).toLowerCase();
|
|
153
158
|
if (!ext) {
|
|
154
159
|
return false;
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
|
|
162
|
+
if (include.length === 0 && SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
158
166
|
const effectiveInclude =
|
|
159
|
-
include.length === 0 ?
|
|
167
|
+
include.length === 0 ? additionalDefaultExtensions : include;
|
|
160
168
|
|
|
161
169
|
return effectiveInclude.some((inc) => {
|
|
162
170
|
const normalizedInc = inc.startsWith(".")
|
|
@@ -211,13 +219,19 @@ export class FileWalker implements WalkerPort {
|
|
|
211
219
|
}
|
|
212
220
|
}
|
|
213
221
|
|
|
214
|
-
for (const
|
|
222
|
+
for (const matchedPath of [...matches].sort()) {
|
|
215
223
|
// Security: Compute safe relative path (validates file is within root)
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
224
|
+
const safePath = await safeRelPath(rootReal, matchedPath);
|
|
225
|
+
if (safePath === null) {
|
|
218
226
|
// File outside root or unresolvable - silently skip (security)
|
|
219
227
|
continue;
|
|
220
228
|
}
|
|
229
|
+
const { absPath, relPath } = safePath;
|
|
230
|
+
|
|
231
|
+
if (isRecordVirtualPath(relPath)) {
|
|
232
|
+
skipped.push({ absPath, relPath, reason: "EXCLUDED" });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
221
235
|
|
|
222
236
|
// Check exclude patterns
|
|
223
237
|
if (matchesCollectionExclusion(relPath, config.exclude)) {
|
|
@@ -230,7 +244,13 @@ export class FileWalker implements WalkerPort {
|
|
|
230
244
|
}
|
|
231
245
|
|
|
232
246
|
// Check include extensions
|
|
233
|
-
if (
|
|
247
|
+
if (
|
|
248
|
+
!matchesInclude(
|
|
249
|
+
relPath,
|
|
250
|
+
config.include,
|
|
251
|
+
config.additionalDefaultExtensions ?? []
|
|
252
|
+
)
|
|
253
|
+
) {
|
|
234
254
|
skipped.push({
|
|
235
255
|
absPath,
|
|
236
256
|
relPath,
|
package/src/llm/errors.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type LlmErrorCode =
|
|
|
18
18
|
| "INVALID_MODEL_FILE"
|
|
19
19
|
| "MODEL_DOWNLOAD_INTERCEPTED"
|
|
20
20
|
| "INFERENCE_FAILED"
|
|
21
|
+
| "EGRESS_DENIED"
|
|
21
22
|
| "TIMEOUT"
|
|
22
23
|
| "OUT_OF_MEMORY"
|
|
23
24
|
| "INVALID_URI"
|
|
@@ -202,6 +203,15 @@ export function inferenceFailedError(uri: string, cause?: unknown): LlmError {
|
|
|
202
203
|
});
|
|
203
204
|
}
|
|
204
205
|
|
|
206
|
+
export function egressDeniedInferenceError(cause?: unknown): LlmError {
|
|
207
|
+
return llmError("EGRESS_DENIED", {
|
|
208
|
+
message: "Operation blocked by collection egress policy",
|
|
209
|
+
retryable: false,
|
|
210
|
+
cause,
|
|
211
|
+
suggestion: "Review the collection egress policy and model destination.",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
205
215
|
export function timeoutError(
|
|
206
216
|
uri: string,
|
|
207
217
|
operation: "load" | "inference",
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/** Policy-gated, DNS-pinned HTTP transport shared by inference adapters. */
|
|
2
|
+
|
|
3
|
+
import type { Collection } from "../config/types";
|
|
4
|
+
import type { CollectionEgressState } from "../core/egress-policy";
|
|
5
|
+
import type { EgressDestinationZone } from "../core/egress-policy";
|
|
6
|
+
import type {
|
|
7
|
+
HttpDestinationPolicyOptions,
|
|
8
|
+
HttpDestinationResolver,
|
|
9
|
+
PinnedHttpFetch,
|
|
10
|
+
} from "./http-policy";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
collectionEgressStates,
|
|
14
|
+
EgressDeniedError,
|
|
15
|
+
maximumDestinationZoneForCollections,
|
|
16
|
+
} from "../core/egress-enforcement";
|
|
17
|
+
import { evaluateEgressPolicy } from "../core/egress-policy";
|
|
18
|
+
import { EgressProvenanceError } from "../core/egress-provenance";
|
|
19
|
+
import { classifyHttpDestination, prepareHttpDestination } from "./http-policy";
|
|
20
|
+
|
|
21
|
+
const REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
|
|
22
|
+
|
|
23
|
+
export interface HttpInferenceOptions {
|
|
24
|
+
collections: readonly Collection[];
|
|
25
|
+
collectionNames: readonly string[];
|
|
26
|
+
authenticated?: boolean;
|
|
27
|
+
operationAuthorized?: boolean;
|
|
28
|
+
resolver?: HttpDestinationResolver;
|
|
29
|
+
fetchFn?: PinnedHttpFetch;
|
|
30
|
+
env?: HttpDestinationPolicyOptions["env"];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const scopedStates = (
|
|
34
|
+
options: HttpInferenceOptions
|
|
35
|
+
): readonly CollectionEgressState[] => {
|
|
36
|
+
try {
|
|
37
|
+
return collectionEgressStates(options.collections, options.collectionNames);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error instanceof EgressProvenanceError) return [];
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const enforce = (
|
|
45
|
+
states: readonly CollectionEgressState[],
|
|
46
|
+
zone: EgressDestinationZone,
|
|
47
|
+
options: HttpInferenceOptions
|
|
48
|
+
): void => {
|
|
49
|
+
const decision = evaluateEgressPolicy({
|
|
50
|
+
collections: states,
|
|
51
|
+
action: "remote_inference",
|
|
52
|
+
destination: { zone },
|
|
53
|
+
caller: {
|
|
54
|
+
authenticated: options.authenticated ?? true,
|
|
55
|
+
operationAuthorized: options.operationAuthorized ?? true,
|
|
56
|
+
},
|
|
57
|
+
contentClass: "source",
|
|
58
|
+
});
|
|
59
|
+
if (!decision.allowed) throw new EgressDeniedError(decision);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const requestHttpInference = async (
|
|
63
|
+
rawUrl: string,
|
|
64
|
+
init: BunFetchRequestInit,
|
|
65
|
+
options: HttpInferenceOptions
|
|
66
|
+
): Promise<Response> => {
|
|
67
|
+
const states = scopedStates(options);
|
|
68
|
+
if (states.length === 0) {
|
|
69
|
+
enforce(states, "remote", options);
|
|
70
|
+
}
|
|
71
|
+
const maximumZone = maximumDestinationZoneForCollections(
|
|
72
|
+
options.collections,
|
|
73
|
+
options.collectionNames
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// DNS-only classification carries no headers, body, credentials, or model
|
|
77
|
+
// metadata. Policy evaluates the proven zone before transport preparation.
|
|
78
|
+
const classification = await classifyHttpDestination(rawUrl, {
|
|
79
|
+
resolver: options.resolver,
|
|
80
|
+
});
|
|
81
|
+
if (!classification.ok) {
|
|
82
|
+
throw new EgressDeniedError(
|
|
83
|
+
evaluateEgressPolicy({
|
|
84
|
+
collections: states,
|
|
85
|
+
action: "remote_inference",
|
|
86
|
+
destination: { zone: classification.classification.zone },
|
|
87
|
+
caller: {
|
|
88
|
+
authenticated: options.authenticated ?? true,
|
|
89
|
+
operationAuthorized: false,
|
|
90
|
+
},
|
|
91
|
+
contentClass: "source",
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
enforce(states, classification.classification.zone, options);
|
|
96
|
+
const url = new URL(rawUrl);
|
|
97
|
+
|
|
98
|
+
let prepared = await prepareHttpDestination(url.href, {
|
|
99
|
+
maximumZone,
|
|
100
|
+
resolver: options.resolver,
|
|
101
|
+
remoteProvider: classification.classification.zone === "remote",
|
|
102
|
+
env: options.env,
|
|
103
|
+
});
|
|
104
|
+
if (!prepared.ok) {
|
|
105
|
+
throw new EgressDeniedError(
|
|
106
|
+
evaluateEgressPolicy({
|
|
107
|
+
collections: states,
|
|
108
|
+
action: "remote_inference",
|
|
109
|
+
destination: { zone: prepared.classification.zone },
|
|
110
|
+
caller: {
|
|
111
|
+
authenticated: options.authenticated ?? true,
|
|
112
|
+
operationAuthorized: false,
|
|
113
|
+
},
|
|
114
|
+
contentClass: "source",
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let currentUrl = url;
|
|
120
|
+
for (;;) {
|
|
121
|
+
enforce(states, prepared.value.classification.zone, options);
|
|
122
|
+
const connection = await prepared.value.acquireConnection();
|
|
123
|
+
if (!connection.ok) {
|
|
124
|
+
throw new EgressDeniedError(
|
|
125
|
+
evaluateEgressPolicy({
|
|
126
|
+
collections: states,
|
|
127
|
+
action: "remote_inference",
|
|
128
|
+
destination: { zone: connection.classification.zone },
|
|
129
|
+
caller: {
|
|
130
|
+
authenticated: options.authenticated ?? true,
|
|
131
|
+
operationAuthorized: false,
|
|
132
|
+
},
|
|
133
|
+
contentClass: "source",
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
const response = await connection.value.request(init, options.fetchFn);
|
|
138
|
+
if (!REDIRECT_STATUSES.has(response.status)) return response;
|
|
139
|
+
|
|
140
|
+
const location = response.headers.get("location");
|
|
141
|
+
if (!location) return response;
|
|
142
|
+
const nextUrl = new URL(location, currentUrl);
|
|
143
|
+
if (nextUrl.origin.toLowerCase() !== currentUrl.origin.toLowerCase()) {
|
|
144
|
+
throw new EgressDeniedError(
|
|
145
|
+
evaluateEgressPolicy({
|
|
146
|
+
collections: states,
|
|
147
|
+
action: "remote_inference",
|
|
148
|
+
destination: { zone: prepared.value.classification.zone },
|
|
149
|
+
caller: {
|
|
150
|
+
authenticated: options.authenticated ?? true,
|
|
151
|
+
operationAuthorized: false,
|
|
152
|
+
},
|
|
153
|
+
contentClass: "source",
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const next = await prepared.value.followRedirect(nextUrl.href);
|
|
158
|
+
if (!next.ok) {
|
|
159
|
+
throw new EgressDeniedError(
|
|
160
|
+
evaluateEgressPolicy({
|
|
161
|
+
collections: states,
|
|
162
|
+
action: "remote_inference",
|
|
163
|
+
destination: { zone: next.classification.zone },
|
|
164
|
+
caller: {
|
|
165
|
+
authenticated: options.authenticated ?? true,
|
|
166
|
+
operationAuthorized: false,
|
|
167
|
+
},
|
|
168
|
+
contentClass: "source",
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
currentUrl = nextUrl;
|
|
173
|
+
prepared = next;
|
|
174
|
+
}
|
|
175
|
+
};
|