@nocobase/plugin-idp-oauth 2.1.0-alpha.16 → 2.1.0-alpha.18
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/build.config.ts +1 -1
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/light-my-request/package.json +1 -1
- package/dist/node_modules/undici/LICENSE +21 -0
- package/dist/node_modules/undici/README.md +741 -0
- package/dist/node_modules/undici/docs/docs/api/Agent.md +84 -0
- package/dist/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
- package/dist/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
- package/dist/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
- package/dist/node_modules/undici/docs/docs/api/Client.md +285 -0
- package/dist/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
- package/dist/node_modules/undici/docs/docs/api/Connector.md +115 -0
- package/dist/node_modules/undici/docs/docs/api/ContentType.md +57 -0
- package/dist/node_modules/undici/docs/docs/api/Cookies.md +101 -0
- package/dist/node_modules/undici/docs/docs/api/Debug.md +62 -0
- package/dist/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
- package/dist/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
- package/dist/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
- package/dist/node_modules/undici/docs/docs/api/Errors.md +49 -0
- package/dist/node_modules/undici/docs/docs/api/EventSource.md +45 -0
- package/dist/node_modules/undici/docs/docs/api/Fetch.md +60 -0
- package/dist/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
- package/dist/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
- package/dist/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
- package/dist/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
- package/dist/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
- package/dist/node_modules/undici/docs/docs/api/MockClient.md +81 -0
- package/dist/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
- package/dist/node_modules/undici/docs/docs/api/MockPool.md +555 -0
- package/dist/node_modules/undici/docs/docs/api/Pool.md +84 -0
- package/dist/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
- package/dist/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
- package/dist/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
- package/dist/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
- package/dist/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
- package/dist/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
- package/dist/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
- package/dist/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +274 -0
- package/dist/node_modules/undici/docs/docs/api/Util.md +25 -0
- package/dist/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
- package/dist/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
- package/dist/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
- package/dist/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
- package/dist/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
- package/dist/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
- package/dist/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
- package/dist/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
- package/dist/node_modules/undici/index-fetch.js +65 -0
- package/dist/node_modules/undici/index.d.ts +3 -0
- package/dist/node_modules/undici/index.js +234 -0
- package/dist/node_modules/undici/lib/api/abort-signal.js +59 -0
- package/dist/node_modules/undici/lib/api/api-connect.js +110 -0
- package/dist/node_modules/undici/lib/api/api-pipeline.js +252 -0
- package/dist/node_modules/undici/lib/api/api-request.js +214 -0
- package/dist/node_modules/undici/lib/api/api-stream.js +209 -0
- package/dist/node_modules/undici/lib/api/api-upgrade.js +111 -0
- package/dist/node_modules/undici/lib/api/index.js +7 -0
- package/dist/node_modules/undici/lib/api/readable.js +580 -0
- package/dist/node_modules/undici/lib/cache/memory-cache-store.js +234 -0
- package/dist/node_modules/undici/lib/cache/sqlite-cache-store.js +461 -0
- package/dist/node_modules/undici/lib/core/connect.js +137 -0
- package/dist/node_modules/undici/lib/core/constants.js +143 -0
- package/dist/node_modules/undici/lib/core/diagnostics.js +227 -0
- package/dist/node_modules/undici/lib/core/errors.js +477 -0
- package/dist/node_modules/undici/lib/core/request.js +438 -0
- package/dist/node_modules/undici/lib/core/socks5-client.js +407 -0
- package/dist/node_modules/undici/lib/core/socks5-utils.js +203 -0
- package/dist/node_modules/undici/lib/core/symbols.js +75 -0
- package/dist/node_modules/undici/lib/core/tree.js +160 -0
- package/dist/node_modules/undici/lib/core/util.js +992 -0
- package/dist/node_modules/undici/lib/dispatcher/agent.js +158 -0
- package/dist/node_modules/undici/lib/dispatcher/balanced-pool.js +219 -0
- package/dist/node_modules/undici/lib/dispatcher/client-h1.js +1610 -0
- package/dist/node_modules/undici/lib/dispatcher/client-h2.js +995 -0
- package/dist/node_modules/undici/lib/dispatcher/client.js +659 -0
- package/dist/node_modules/undici/lib/dispatcher/dispatcher-base.js +165 -0
- package/dist/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
- package/dist/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
- package/dist/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
- package/dist/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
- package/dist/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
- package/dist/node_modules/undici/lib/dispatcher/pool.js +118 -0
- package/dist/node_modules/undici/lib/dispatcher/proxy-agent.js +318 -0
- package/dist/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
- package/dist/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
- package/dist/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +249 -0
- package/dist/node_modules/undici/lib/encoding/index.js +33 -0
- package/dist/node_modules/undici/lib/global.js +50 -0
- package/dist/node_modules/undici/lib/handler/cache-handler.js +578 -0
- package/dist/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
- package/dist/node_modules/undici/lib/handler/decorator-handler.js +67 -0
- package/dist/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
- package/dist/node_modules/undici/lib/handler/redirect-handler.js +238 -0
- package/dist/node_modules/undici/lib/handler/retry-handler.js +394 -0
- package/dist/node_modules/undici/lib/handler/unwrap-handler.js +100 -0
- package/dist/node_modules/undici/lib/handler/wrap-handler.js +105 -0
- package/dist/node_modules/undici/lib/interceptor/cache.js +495 -0
- package/dist/node_modules/undici/lib/interceptor/decompress.js +259 -0
- package/dist/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
- package/dist/node_modules/undici/lib/interceptor/dns.js +571 -0
- package/dist/node_modules/undici/lib/interceptor/dump.js +112 -0
- package/dist/node_modules/undici/lib/interceptor/redirect.js +21 -0
- package/dist/node_modules/undici/lib/interceptor/response-error.js +95 -0
- package/dist/node_modules/undici/lib/interceptor/retry.js +19 -0
- package/dist/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/dist/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
- package/dist/node_modules/undici/lib/llhttp/constants.js +531 -0
- package/dist/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
- package/dist/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
- package/dist/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
- package/dist/node_modules/undici/lib/llhttp/utils.js +12 -0
- package/dist/node_modules/undici/lib/mock/mock-agent.js +232 -0
- package/dist/node_modules/undici/lib/mock/mock-call-history.js +248 -0
- package/dist/node_modules/undici/lib/mock/mock-client.js +68 -0
- package/dist/node_modules/undici/lib/mock/mock-errors.js +29 -0
- package/dist/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
- package/dist/node_modules/undici/lib/mock/mock-pool.js +68 -0
- package/dist/node_modules/undici/lib/mock/mock-symbols.js +32 -0
- package/dist/node_modules/undici/lib/mock/mock-utils.js +486 -0
- package/dist/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
- package/dist/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
- package/dist/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
- package/dist/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
- package/dist/node_modules/undici/lib/util/cache.js +407 -0
- package/dist/node_modules/undici/lib/util/date.js +653 -0
- package/dist/node_modules/undici/lib/util/promise.js +28 -0
- package/dist/node_modules/undici/lib/util/runtime-features.js +124 -0
- package/dist/node_modules/undici/lib/util/stats.js +32 -0
- package/dist/node_modules/undici/lib/util/timers.js +425 -0
- package/dist/node_modules/undici/lib/web/cache/cache.js +864 -0
- package/dist/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
- package/dist/node_modules/undici/lib/web/cache/util.js +45 -0
- package/dist/node_modules/undici/lib/web/cookies/constants.js +12 -0
- package/dist/node_modules/undici/lib/web/cookies/index.js +199 -0
- package/dist/node_modules/undici/lib/web/cookies/parse.js +322 -0
- package/dist/node_modules/undici/lib/web/cookies/util.js +282 -0
- package/dist/node_modules/undici/lib/web/eventsource/eventsource-stream.js +399 -0
- package/dist/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
- package/dist/node_modules/undici/lib/web/eventsource/util.js +29 -0
- package/dist/node_modules/undici/lib/web/fetch/LICENSE +21 -0
- package/dist/node_modules/undici/lib/web/fetch/body.js +509 -0
- package/dist/node_modules/undici/lib/web/fetch/constants.js +131 -0
- package/dist/node_modules/undici/lib/web/fetch/data-url.js +596 -0
- package/dist/node_modules/undici/lib/web/fetch/formdata-parser.js +575 -0
- package/dist/node_modules/undici/lib/web/fetch/formdata.js +259 -0
- package/dist/node_modules/undici/lib/web/fetch/global.js +40 -0
- package/dist/node_modules/undici/lib/web/fetch/headers.js +719 -0
- package/dist/node_modules/undici/lib/web/fetch/index.js +2397 -0
- package/dist/node_modules/undici/lib/web/fetch/request.js +1115 -0
- package/dist/node_modules/undici/lib/web/fetch/response.js +641 -0
- package/dist/node_modules/undici/lib/web/fetch/util.js +1520 -0
- package/dist/node_modules/undici/lib/web/infra/index.js +229 -0
- package/dist/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
- package/dist/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
- package/dist/node_modules/undici/lib/web/webidl/index.js +1006 -0
- package/dist/node_modules/undici/lib/web/websocket/connection.js +329 -0
- package/dist/node_modules/undici/lib/web/websocket/constants.js +126 -0
- package/dist/node_modules/undici/lib/web/websocket/events.js +331 -0
- package/dist/node_modules/undici/lib/web/websocket/frame.js +133 -0
- package/dist/node_modules/undici/lib/web/websocket/permessage-deflate.js +118 -0
- package/dist/node_modules/undici/lib/web/websocket/receiver.js +450 -0
- package/dist/node_modules/undici/lib/web/websocket/sender.js +109 -0
- package/dist/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
- package/dist/node_modules/undici/lib/web/websocket/stream/websocketstream.js +497 -0
- package/dist/node_modules/undici/lib/web/websocket/util.js +347 -0
- package/dist/node_modules/undici/lib/web/websocket/websocket.js +751 -0
- package/dist/node_modules/undici/package.json +152 -0
- package/dist/node_modules/undici/scripts/strip-comments.js +10 -0
- package/dist/node_modules/undici/types/README.md +6 -0
- package/dist/node_modules/undici/types/agent.d.ts +32 -0
- package/dist/node_modules/undici/types/api.d.ts +43 -0
- package/dist/node_modules/undici/types/balanced-pool.d.ts +30 -0
- package/dist/node_modules/undici/types/cache-interceptor.d.ts +179 -0
- package/dist/node_modules/undici/types/cache.d.ts +36 -0
- package/dist/node_modules/undici/types/client-stats.d.ts +15 -0
- package/dist/node_modules/undici/types/client.d.ts +123 -0
- package/dist/node_modules/undici/types/connector.d.ts +36 -0
- package/dist/node_modules/undici/types/content-type.d.ts +21 -0
- package/dist/node_modules/undici/types/cookies.d.ts +30 -0
- package/dist/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
- package/dist/node_modules/undici/types/dispatcher.d.ts +273 -0
- package/dist/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
- package/dist/node_modules/undici/types/errors.d.ts +177 -0
- package/dist/node_modules/undici/types/eventsource.d.ts +66 -0
- package/dist/node_modules/undici/types/fetch.d.ts +231 -0
- package/dist/node_modules/undici/types/formdata.d.ts +114 -0
- package/dist/node_modules/undici/types/global-dispatcher.d.ts +9 -0
- package/dist/node_modules/undici/types/global-origin.d.ts +7 -0
- package/dist/node_modules/undici/types/h2c-client.d.ts +73 -0
- package/dist/node_modules/undici/types/handlers.d.ts +14 -0
- package/dist/node_modules/undici/types/header.d.ts +160 -0
- package/dist/node_modules/undici/types/index.d.ts +91 -0
- package/dist/node_modules/undici/types/interceptors.d.ts +80 -0
- package/dist/node_modules/undici/types/mock-agent.d.ts +68 -0
- package/dist/node_modules/undici/types/mock-call-history.d.ts +111 -0
- package/dist/node_modules/undici/types/mock-client.d.ts +27 -0
- package/dist/node_modules/undici/types/mock-errors.d.ts +12 -0
- package/dist/node_modules/undici/types/mock-interceptor.d.ts +94 -0
- package/dist/node_modules/undici/types/mock-pool.d.ts +27 -0
- package/dist/node_modules/undici/types/patch.d.ts +29 -0
- package/dist/node_modules/undici/types/pool-stats.d.ts +19 -0
- package/dist/node_modules/undici/types/pool.d.ts +41 -0
- package/dist/node_modules/undici/types/proxy-agent.d.ts +29 -0
- package/dist/node_modules/undici/types/readable.d.ts +68 -0
- package/dist/node_modules/undici/types/retry-agent.d.ts +8 -0
- package/dist/node_modules/undici/types/retry-handler.d.ts +125 -0
- package/dist/node_modules/undici/types/round-robin-pool.d.ts +41 -0
- package/dist/node_modules/undici/types/snapshot-agent.d.ts +109 -0
- package/dist/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
- package/dist/node_modules/undici/types/util.d.ts +18 -0
- package/dist/node_modules/undici/types/utility.d.ts +7 -0
- package/dist/node_modules/undici/types/webidl.d.ts +347 -0
- package/dist/node_modules/undici/types/websocket.d.ts +188 -0
- package/dist/server/plugin.d.ts +1 -0
- package/dist/server/plugin.js +13 -0
- package/dist/server/service.js +11 -3
- package/package.json +2 -2
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { InvalidArgumentError } = require('../core/errors')
|
|
4
|
+
const { runtimeFeatures } = require('../util/runtime-features.js')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} HeaderFilters
|
|
8
|
+
* @property {Set<string>} ignore - Set of headers to ignore for matching
|
|
9
|
+
* @property {Set<string>} exclude - Set of headers to exclude from matching
|
|
10
|
+
* @property {Set<string>} match - Set of headers to match (empty means match
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates cached header sets for performance
|
|
15
|
+
*
|
|
16
|
+
* @param {import('./snapshot-recorder').SnapshotRecorderMatchOptions} matchOptions - Matching options for headers
|
|
17
|
+
* @returns {HeaderFilters} - Cached sets for ignore, exclude, and match headers
|
|
18
|
+
*/
|
|
19
|
+
function createHeaderFilters (matchOptions = {}) {
|
|
20
|
+
const { ignoreHeaders = [], excludeHeaders = [], matchHeaders = [], caseSensitive = false } = matchOptions
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
ignore: new Set(ignoreHeaders.map(header => caseSensitive ? header : header.toLowerCase())),
|
|
24
|
+
exclude: new Set(excludeHeaders.map(header => caseSensitive ? header : header.toLowerCase())),
|
|
25
|
+
match: new Set(matchHeaders.map(header => caseSensitive ? header : header.toLowerCase()))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const crypto = runtimeFeatures.has('crypto')
|
|
30
|
+
? require('node:crypto')
|
|
31
|
+
: null
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @callback HashIdFunction
|
|
35
|
+
* @param {string} value - The value to hash
|
|
36
|
+
* @returns {string} - The base64url encoded hash of the value
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generates a hash for a given value
|
|
41
|
+
* @type {HashIdFunction}
|
|
42
|
+
*/
|
|
43
|
+
const hashId = crypto?.hash
|
|
44
|
+
? (value) => crypto.hash('sha256', value, 'base64url')
|
|
45
|
+
: (value) => Buffer.from(value).toString('base64url')
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {(url: string) => boolean} IsUrlExcluded Checks if a URL matches any of the exclude patterns
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/** @typedef {{[key: Lowercase<string>]: string}} NormalizedHeaders */
|
|
52
|
+
/** @typedef {Array<string>} UndiciHeaders */
|
|
53
|
+
/** @typedef {Record<string, string|string[]>} Headers */
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {*} headers
|
|
57
|
+
* @returns {headers is UndiciHeaders}
|
|
58
|
+
*/
|
|
59
|
+
function isUndiciHeaders (headers) {
|
|
60
|
+
return Array.isArray(headers) && (headers.length & 1) === 0
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Factory function to create a URL exclusion checker
|
|
65
|
+
* @param {Array<string| RegExp>} [excludePatterns=[]] - Array of patterns to exclude
|
|
66
|
+
* @returns {IsUrlExcluded} - A function that checks if a URL matches any of the exclude patterns
|
|
67
|
+
*/
|
|
68
|
+
function isUrlExcludedFactory (excludePatterns = []) {
|
|
69
|
+
if (excludePatterns.length === 0) {
|
|
70
|
+
return () => false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return function isUrlExcluded (url) {
|
|
74
|
+
let urlLowerCased
|
|
75
|
+
|
|
76
|
+
for (const pattern of excludePatterns) {
|
|
77
|
+
if (typeof pattern === 'string') {
|
|
78
|
+
if (!urlLowerCased) {
|
|
79
|
+
// Convert URL to lowercase only once
|
|
80
|
+
urlLowerCased = url.toLowerCase()
|
|
81
|
+
}
|
|
82
|
+
// Simple string match (case-insensitive)
|
|
83
|
+
if (urlLowerCased.includes(pattern.toLowerCase())) {
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
} else if (pattern instanceof RegExp) {
|
|
87
|
+
// Regex pattern match
|
|
88
|
+
if (pattern.test(url)) {
|
|
89
|
+
return true
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Normalizes headers for consistent comparison
|
|
100
|
+
*
|
|
101
|
+
* @param {Object|UndiciHeaders} headers - Headers to normalize
|
|
102
|
+
* @returns {NormalizedHeaders} - Normalized headers as a lowercase object
|
|
103
|
+
*/
|
|
104
|
+
function normalizeHeaders (headers) {
|
|
105
|
+
/** @type {NormalizedHeaders} */
|
|
106
|
+
const normalizedHeaders = {}
|
|
107
|
+
|
|
108
|
+
if (!headers) return normalizedHeaders
|
|
109
|
+
|
|
110
|
+
// Handle array format (undici internal format: [name, value, name, value, ...])
|
|
111
|
+
if (isUndiciHeaders(headers)) {
|
|
112
|
+
for (let i = 0; i < headers.length; i += 2) {
|
|
113
|
+
const key = headers[i]
|
|
114
|
+
const value = headers[i + 1]
|
|
115
|
+
if (key && value !== undefined) {
|
|
116
|
+
// Convert Buffers to strings if needed
|
|
117
|
+
const keyStr = Buffer.isBuffer(key) ? key.toString() : key
|
|
118
|
+
const valueStr = Buffer.isBuffer(value) ? value.toString() : value
|
|
119
|
+
normalizedHeaders[keyStr.toLowerCase()] = valueStr
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return normalizedHeaders
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Handle object format
|
|
126
|
+
if (headers && typeof headers === 'object') {
|
|
127
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
128
|
+
if (key && typeof key === 'string') {
|
|
129
|
+
normalizedHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return normalizedHeaders
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const validSnapshotModes = /** @type {const} */ (['record', 'playback', 'update'])
|
|
138
|
+
|
|
139
|
+
/** @typedef {typeof validSnapshotModes[number]} SnapshotMode */
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @param {*} mode - The snapshot mode to validate
|
|
143
|
+
* @returns {asserts mode is SnapshotMode}
|
|
144
|
+
*/
|
|
145
|
+
function validateSnapshotMode (mode) {
|
|
146
|
+
if (!validSnapshotModes.includes(mode)) {
|
|
147
|
+
throw new InvalidArgumentError(`Invalid snapshot mode: ${mode}. Must be one of: ${validSnapshotModes.join(', ')}`)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
createHeaderFilters,
|
|
153
|
+
hashId,
|
|
154
|
+
isUndiciHeaders,
|
|
155
|
+
normalizeHeaders,
|
|
156
|
+
isUrlExcludedFactory,
|
|
157
|
+
validateSnapshotMode
|
|
158
|
+
}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
safeHTTPMethods,
|
|
5
|
+
pathHasQueryOrFragment,
|
|
6
|
+
hasSafeIterator
|
|
7
|
+
} = require('../core/util')
|
|
8
|
+
|
|
9
|
+
const { serializePathWithQuery } = require('../core/util')
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts
|
|
13
|
+
*/
|
|
14
|
+
function makeCacheKey (opts) {
|
|
15
|
+
if (!opts.origin) {
|
|
16
|
+
throw new Error('opts.origin is undefined')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let fullPath = opts.path || '/'
|
|
20
|
+
|
|
21
|
+
if (opts.query && !pathHasQueryOrFragment(opts.path)) {
|
|
22
|
+
fullPath = serializePathWithQuery(fullPath, opts.query)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
origin: opts.origin.toString(),
|
|
27
|
+
method: opts.method,
|
|
28
|
+
path: fullPath,
|
|
29
|
+
headers: opts.headers
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {Record<string, string[] | string>}
|
|
35
|
+
* @returns {Record<string, string[] | string>}
|
|
36
|
+
*/
|
|
37
|
+
function normalizeHeaders (opts) {
|
|
38
|
+
let headers
|
|
39
|
+
if (opts.headers == null) {
|
|
40
|
+
headers = {}
|
|
41
|
+
} else if (typeof opts.headers === 'object') {
|
|
42
|
+
headers = {}
|
|
43
|
+
|
|
44
|
+
if (hasSafeIterator(opts.headers)) {
|
|
45
|
+
for (const x of opts.headers) {
|
|
46
|
+
if (!Array.isArray(x)) {
|
|
47
|
+
throw new Error('opts.headers is not a valid header map')
|
|
48
|
+
}
|
|
49
|
+
const [key, val] = x
|
|
50
|
+
if (typeof key !== 'string' || typeof val !== 'string') {
|
|
51
|
+
throw new Error('opts.headers is not a valid header map')
|
|
52
|
+
}
|
|
53
|
+
headers[key.toLowerCase()] = val
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
for (const key of Object.keys(opts.headers)) {
|
|
57
|
+
headers[key.toLowerCase()] = opts.headers[key]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
throw new Error('opts.headers is not an object')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return headers
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {any} key
|
|
69
|
+
*/
|
|
70
|
+
function assertCacheKey (key) {
|
|
71
|
+
if (typeof key !== 'object') {
|
|
72
|
+
throw new TypeError(`expected key to be object, got ${typeof key}`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const property of ['origin', 'method', 'path']) {
|
|
76
|
+
if (typeof key[property] !== 'string') {
|
|
77
|
+
throw new TypeError(`expected key.${property} to be string, got ${typeof key[property]}`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (key.headers !== undefined && typeof key.headers !== 'object') {
|
|
82
|
+
throw new TypeError(`expected headers to be object, got ${typeof key}`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {any} value
|
|
88
|
+
*/
|
|
89
|
+
function assertCacheValue (value) {
|
|
90
|
+
if (typeof value !== 'object') {
|
|
91
|
+
throw new TypeError(`expected value to be object, got ${typeof value}`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
for (const property of ['statusCode', 'cachedAt', 'staleAt', 'deleteAt']) {
|
|
95
|
+
if (typeof value[property] !== 'number') {
|
|
96
|
+
throw new TypeError(`expected value.${property} to be number, got ${typeof value[property]}`)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (typeof value.statusMessage !== 'string') {
|
|
101
|
+
throw new TypeError(`expected value.statusMessage to be string, got ${typeof value.statusMessage}`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (value.headers != null && typeof value.headers !== 'object') {
|
|
105
|
+
throw new TypeError(`expected value.rawHeaders to be object, got ${typeof value.headers}`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (value.vary !== undefined && typeof value.vary !== 'object') {
|
|
109
|
+
throw new TypeError(`expected value.vary to be object, got ${typeof value.vary}`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (value.etag !== undefined && typeof value.etag !== 'string') {
|
|
113
|
+
throw new TypeError(`expected value.etag to be string, got ${typeof value.etag}`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control
|
|
119
|
+
* @see https://www.iana.org/assignments/http-cache-directives/http-cache-directives.xhtml
|
|
120
|
+
|
|
121
|
+
* @param {string | string[]} header
|
|
122
|
+
* @returns {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
|
|
123
|
+
*/
|
|
124
|
+
function parseCacheControlHeader (header) {
|
|
125
|
+
/**
|
|
126
|
+
* @type {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
|
|
127
|
+
*/
|
|
128
|
+
const output = {}
|
|
129
|
+
|
|
130
|
+
let directives
|
|
131
|
+
if (Array.isArray(header)) {
|
|
132
|
+
directives = []
|
|
133
|
+
|
|
134
|
+
for (const directive of header) {
|
|
135
|
+
directives.push(...directive.split(','))
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
directives = header.split(',')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < directives.length; i++) {
|
|
142
|
+
const directive = directives[i].toLowerCase()
|
|
143
|
+
const keyValueDelimiter = directive.indexOf('=')
|
|
144
|
+
|
|
145
|
+
let key
|
|
146
|
+
let value
|
|
147
|
+
if (keyValueDelimiter !== -1) {
|
|
148
|
+
key = directive.substring(0, keyValueDelimiter).trimStart()
|
|
149
|
+
value = directive.substring(keyValueDelimiter + 1)
|
|
150
|
+
} else {
|
|
151
|
+
key = directive.trim()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
switch (key) {
|
|
155
|
+
case 'min-fresh':
|
|
156
|
+
case 'max-stale':
|
|
157
|
+
case 'max-age':
|
|
158
|
+
case 's-maxage':
|
|
159
|
+
case 'stale-while-revalidate':
|
|
160
|
+
case 'stale-if-error': {
|
|
161
|
+
if (value === undefined || value[0] === ' ') {
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
value.length >= 2 &&
|
|
167
|
+
value[0] === '"' &&
|
|
168
|
+
value[value.length - 1] === '"'
|
|
169
|
+
) {
|
|
170
|
+
value = value.substring(1, value.length - 1)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const parsedValue = parseInt(value, 10)
|
|
174
|
+
// eslint-disable-next-line no-self-compare
|
|
175
|
+
if (parsedValue !== parsedValue) {
|
|
176
|
+
continue
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (key === 'max-age' && key in output && output[key] >= parsedValue) {
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
output[key] = parsedValue
|
|
184
|
+
|
|
185
|
+
break
|
|
186
|
+
}
|
|
187
|
+
case 'private':
|
|
188
|
+
case 'no-cache': {
|
|
189
|
+
if (value) {
|
|
190
|
+
// The private and no-cache directives can be unqualified (aka just
|
|
191
|
+
// `private` or `no-cache`) or qualified (w/ a value). When they're
|
|
192
|
+
// qualified, it's a list of headers like `no-cache=header1`,
|
|
193
|
+
// `no-cache="header1"`, or `no-cache="header1, header2"`
|
|
194
|
+
// If we're given multiple headers, the comma messes us up since
|
|
195
|
+
// we split the full header by commas. So, let's loop through the
|
|
196
|
+
// remaining parts in front of us until we find one that ends in a
|
|
197
|
+
// quote. We can then just splice all of the parts in between the
|
|
198
|
+
// starting quote and the ending quote out of the directives array
|
|
199
|
+
// and continue parsing like normal.
|
|
200
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#name-no-cache-2
|
|
201
|
+
if (value[0] === '"') {
|
|
202
|
+
// Something like `no-cache="some-header"` OR `no-cache="some-header, another-header"`.
|
|
203
|
+
|
|
204
|
+
// Add the first header on and cut off the leading quote
|
|
205
|
+
const headers = [value.substring(1)]
|
|
206
|
+
|
|
207
|
+
let foundEndingQuote = value[value.length - 1] === '"'
|
|
208
|
+
if (!foundEndingQuote) {
|
|
209
|
+
// Something like `no-cache="some-header, another-header"`
|
|
210
|
+
// This can still be something invalid, e.g. `no-cache="some-header, ...`
|
|
211
|
+
for (let j = i + 1; j < directives.length; j++) {
|
|
212
|
+
const nextPart = directives[j]
|
|
213
|
+
const nextPartLength = nextPart.length
|
|
214
|
+
|
|
215
|
+
headers.push(nextPart.trim())
|
|
216
|
+
|
|
217
|
+
if (nextPartLength !== 0 && nextPart[nextPartLength - 1] === '"') {
|
|
218
|
+
foundEndingQuote = true
|
|
219
|
+
break
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (foundEndingQuote) {
|
|
225
|
+
let lastHeader = headers[headers.length - 1]
|
|
226
|
+
if (lastHeader[lastHeader.length - 1] === '"') {
|
|
227
|
+
lastHeader = lastHeader.substring(0, lastHeader.length - 1)
|
|
228
|
+
headers[headers.length - 1] = lastHeader
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (key in output) {
|
|
232
|
+
output[key] = output[key].concat(headers)
|
|
233
|
+
} else {
|
|
234
|
+
output[key] = headers
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
// Something like `no-cache="some-header"`
|
|
239
|
+
if (key in output) {
|
|
240
|
+
output[key] = output[key].concat(value)
|
|
241
|
+
} else {
|
|
242
|
+
output[key] = [value]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
break
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// eslint-disable-next-line no-fallthrough
|
|
250
|
+
case 'public':
|
|
251
|
+
case 'no-store':
|
|
252
|
+
case 'must-revalidate':
|
|
253
|
+
case 'proxy-revalidate':
|
|
254
|
+
case 'immutable':
|
|
255
|
+
case 'no-transform':
|
|
256
|
+
case 'must-understand':
|
|
257
|
+
case 'only-if-cached':
|
|
258
|
+
if (value) {
|
|
259
|
+
// These are qualified (something like `public=...`) when they aren't
|
|
260
|
+
// allowed to be, skip
|
|
261
|
+
continue
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
output[key] = true
|
|
265
|
+
break
|
|
266
|
+
default:
|
|
267
|
+
// Ignore unknown directives as per https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.3-1
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return output
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
277
|
+
* @param {Record<string, string | string[]>} headers Request headers
|
|
278
|
+
* @returns {Record<string, string | string[]>}
|
|
279
|
+
*/
|
|
280
|
+
function parseVaryHeader (varyHeader, headers) {
|
|
281
|
+
if (typeof varyHeader === 'string' && varyHeader.includes('*')) {
|
|
282
|
+
return headers
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const output = /** @type {Record<string, string | string[] | null>} */ ({})
|
|
286
|
+
|
|
287
|
+
const varyingHeaders = typeof varyHeader === 'string'
|
|
288
|
+
? varyHeader.split(',')
|
|
289
|
+
: varyHeader
|
|
290
|
+
|
|
291
|
+
for (const header of varyingHeaders) {
|
|
292
|
+
const trimmedHeader = header.trim().toLowerCase()
|
|
293
|
+
|
|
294
|
+
output[trimmedHeader] = headers[trimmedHeader] ?? null
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return output
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Note: this deviates from the spec a little. Empty etags ("", W/"") are valid,
|
|
302
|
+
* however, including them in cached resposnes serves little to no purpose.
|
|
303
|
+
*
|
|
304
|
+
* @see https://www.rfc-editor.org/rfc/rfc9110.html#name-etag
|
|
305
|
+
*
|
|
306
|
+
* @param {string} etag
|
|
307
|
+
* @returns {boolean}
|
|
308
|
+
*/
|
|
309
|
+
function isEtagUsable (etag) {
|
|
310
|
+
if (etag.length <= 2) {
|
|
311
|
+
// Shortest an etag can be is two chars (just ""). This is where we deviate
|
|
312
|
+
// from the spec requiring a min of 3 chars however
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (etag[0] === '"' && etag[etag.length - 1] === '"') {
|
|
317
|
+
// ETag: ""asd123"" or ETag: "W/"asd123"", kinda undefined behavior in the
|
|
318
|
+
// spec. Some servers will accept these while others don't.
|
|
319
|
+
// ETag: "asd123"
|
|
320
|
+
return !(etag[1] === '"' || etag.startsWith('"W/'))
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (etag.startsWith('W/"') && etag[etag.length - 1] === '"') {
|
|
324
|
+
// ETag: W/"", also where we deviate from the spec & require a min of 3
|
|
325
|
+
// chars
|
|
326
|
+
// ETag: for W/"", W/"asd123"
|
|
327
|
+
return etag.length !== 4
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Anything else
|
|
331
|
+
return false
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @param {unknown} store
|
|
336
|
+
* @returns {asserts store is import('../../types/cache-interceptor.d.ts').default.CacheStore}
|
|
337
|
+
*/
|
|
338
|
+
function assertCacheStore (store, name = 'CacheStore') {
|
|
339
|
+
if (typeof store !== 'object' || store === null) {
|
|
340
|
+
throw new TypeError(`expected type of ${name} to be a CacheStore, got ${store === null ? 'null' : typeof store}`)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
for (const fn of ['get', 'createWriteStream', 'delete']) {
|
|
344
|
+
if (typeof store[fn] !== 'function') {
|
|
345
|
+
throw new TypeError(`${name} needs to have a \`${fn}()\` function`)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* @param {unknown} methods
|
|
351
|
+
* @returns {asserts methods is import('../../types/cache-interceptor.d.ts').default.CacheMethods[]}
|
|
352
|
+
*/
|
|
353
|
+
function assertCacheMethods (methods, name = 'CacheMethods') {
|
|
354
|
+
if (!Array.isArray(methods)) {
|
|
355
|
+
throw new TypeError(`expected type of ${name} needs to be an array, got ${methods === null ? 'null' : typeof methods}`)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (methods.length === 0) {
|
|
359
|
+
throw new TypeError(`${name} needs to have at least one method`)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
for (const method of methods) {
|
|
363
|
+
if (!safeHTTPMethods.includes(method)) {
|
|
364
|
+
throw new TypeError(`element of ${name}-array needs to be one of following values: ${safeHTTPMethods.join(', ')}, got ${method}`)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Creates a string key for request deduplication purposes.
|
|
371
|
+
* This key is used to identify in-flight requests that can be shared.
|
|
372
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
|
|
373
|
+
* @param {Set<string>} [excludeHeaders] Set of lowercase header names to exclude from the key
|
|
374
|
+
* @returns {string}
|
|
375
|
+
*/
|
|
376
|
+
function makeDeduplicationKey (cacheKey, excludeHeaders) {
|
|
377
|
+
// Create a deterministic string key from the cache key
|
|
378
|
+
// Include origin, method, path, and sorted headers
|
|
379
|
+
let key = `${cacheKey.origin}:${cacheKey.method}:${cacheKey.path}`
|
|
380
|
+
|
|
381
|
+
if (cacheKey.headers) {
|
|
382
|
+
const sortedHeaders = Object.keys(cacheKey.headers).sort()
|
|
383
|
+
for (const header of sortedHeaders) {
|
|
384
|
+
// Skip excluded headers
|
|
385
|
+
if (excludeHeaders?.has(header.toLowerCase())) {
|
|
386
|
+
continue
|
|
387
|
+
}
|
|
388
|
+
const value = cacheKey.headers[header]
|
|
389
|
+
key += `:${header}=${Array.isArray(value) ? value.join(',') : value}`
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return key
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
module.exports = {
|
|
397
|
+
makeCacheKey,
|
|
398
|
+
normalizeHeaders,
|
|
399
|
+
assertCacheKey,
|
|
400
|
+
assertCacheValue,
|
|
401
|
+
parseCacheControlHeader,
|
|
402
|
+
parseVaryHeader,
|
|
403
|
+
isEtagUsable,
|
|
404
|
+
assertCacheMethods,
|
|
405
|
+
assertCacheStore,
|
|
406
|
+
makeDeduplicationKey
|
|
407
|
+
}
|