@fetchkit/ffetch 5.4.12 → 5.5.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/dist/plugins/dedupe.cjs +19 -34
- package/dist/plugins/dedupe.cjs.map +1 -1
- package/dist/plugins/dedupe.js +19 -34
- package/dist/plugins/dedupe.js.map +1 -1
- package/package.json +1 -1
package/dist/plugins/dedupe.cjs
CHANGED
|
@@ -110,45 +110,30 @@ function dedupePlugin(options = {}) {
|
|
|
110
110
|
}
|
|
111
111
|
const existing = inFlight.get(key);
|
|
112
112
|
if (existing) {
|
|
113
|
-
return
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
existing.waiters.push({ resolve, reject });
|
|
115
|
+
});
|
|
114
116
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let rejectFn;
|
|
118
|
-
const placeholder = new Promise((resolve, reject) => {
|
|
119
|
-
resolveFn = (value) => {
|
|
120
|
-
if (!settled) {
|
|
121
|
-
settled = true;
|
|
122
|
-
resolve(value);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
rejectFn = (reason) => {
|
|
126
|
-
if (!settled) {
|
|
127
|
-
settled = true;
|
|
128
|
-
reject(reason);
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
});
|
|
132
|
-
placeholder.catch(() => void 0);
|
|
117
|
+
const waiters = [];
|
|
118
|
+
const actualPromise = next(ctx);
|
|
133
119
|
inFlight.set(key, {
|
|
134
|
-
promise:
|
|
135
|
-
|
|
136
|
-
reject: rejectFn,
|
|
120
|
+
promise: actualPromise,
|
|
121
|
+
waiters,
|
|
137
122
|
createdAt: Date.now()
|
|
138
123
|
});
|
|
139
124
|
startSweeper();
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
125
|
+
actualPromise.then(
|
|
126
|
+
(result) => {
|
|
127
|
+
for (const waiter of waiters) {
|
|
128
|
+
waiter.resolve(result.clone());
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
(error) => {
|
|
132
|
+
for (const waiter of waiters) {
|
|
133
|
+
waiter.reject(error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
);
|
|
152
137
|
return actualPromise.finally(() => {
|
|
153
138
|
const current = inFlight.get(key);
|
|
154
139
|
if (current?.promise === actualPromise) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/dedupe.ts","../../src/dedupeRequestHash.ts"],"sourcesContent":["import type { ClientPlugin, PluginRequestContext } from '../plugins.js'\nimport {\n dedupeRequestHash,\n type DedupeHashParams,\n} from '../dedupeRequestHash.js'\n\ntype
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/dedupe.ts","../../src/dedupeRequestHash.ts"],"sourcesContent":["import type { ClientPlugin, PluginRequestContext } from '../plugins.js'\nimport {\n dedupeRequestHash,\n type DedupeHashParams,\n} from '../dedupeRequestHash.js'\n\ntype Waiter = {\n resolve: (value: Response) => void\n reject: (reason?: unknown) => void\n}\n\ntype DedupeEntry = {\n promise: Promise<Response>\n waiters: Waiter[]\n createdAt: number\n}\n\nexport type DedupePluginOptions = {\n hashFn?: (params: DedupeHashParams) => string | undefined\n ttl?: number\n sweepInterval?: number\n order?: number\n}\n\nfunction contextToHashParams(ctx: PluginRequestContext): DedupeHashParams {\n return {\n method: ctx.request.method,\n url: ctx.request.url,\n body: (ctx.init.body ?? null) as DedupeHashParams['body'],\n headers: ctx.request.headers,\n signal:\n ctx.init.signal === undefined || ctx.init.signal === null\n ? undefined\n : ctx.init.signal,\n requestInit: ctx.init,\n request: ctx.request,\n }\n}\n\nexport function dedupePlugin(options: DedupePluginOptions = {}): ClientPlugin {\n const {\n hashFn = dedupeRequestHash,\n ttl,\n sweepInterval = 5000,\n order = 10,\n } = options\n\n const inFlight = new Map<string, DedupeEntry>()\n let sweeper: ReturnType<typeof setInterval> | undefined\n\n function startSweeper() {\n if (sweeper || typeof ttl !== 'number' || ttl <= 0) return\n sweeper = setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of inFlight.entries()) {\n if (now - entry.createdAt > ttl) {\n inFlight.delete(key)\n }\n }\n if (inFlight.size === 0 && sweeper) {\n clearInterval(sweeper)\n sweeper = undefined\n }\n }, sweepInterval)\n }\n\n function stopSweeperIfIdle() {\n if (inFlight.size === 0 && sweeper) {\n clearInterval(sweeper)\n sweeper = undefined\n }\n }\n\n return {\n name: 'dedupe',\n order,\n wrapDispatch: (next) => async (ctx) => {\n const key = hashFn(contextToHashParams(ctx))\n ctx.state.dedupeKey = key\n\n if (!key) {\n return next(ctx)\n }\n\n const existing = inFlight.get(key)\n if (existing) {\n return new Promise<Response>((resolve, reject) => {\n existing.waiters.push({ resolve, reject })\n })\n }\n\n const waiters: Waiter[] = []\n const actualPromise = next(ctx)\n\n inFlight.set(key, {\n promise: actualPromise,\n waiters,\n createdAt: Date.now(),\n })\n startSweeper()\n\n actualPromise.then(\n (result) => {\n for (const waiter of waiters) {\n waiter.resolve(result.clone())\n }\n },\n (error) => {\n for (const waiter of waiters) {\n waiter.reject(error)\n }\n }\n )\n\n return actualPromise.finally(() => {\n const current = inFlight.get(key)\n if (current?.promise === actualPromise) {\n inFlight.delete(key)\n stopSweeperIfIdle()\n }\n })\n },\n }\n}\n\nexport { dedupeRequestHash }\nexport type { DedupeHashParams }\n","export type DedupeHashParams = {\n method: string\n url: string\n body:\n | string\n | FormData\n | URLSearchParams\n | Blob\n | ArrayBuffer\n | BufferSource\n | null\n | ReadableStream<unknown>\n headers?: Headers | Record<string, string>\n signal?: AbortSignal\n requestInit?: RequestInit\n request?: Request\n}\n\nexport function dedupeRequestHash(\n params: DedupeHashParams\n): string | undefined {\n const { method, url, body } = params\n let bodyString = ''\n if (body instanceof FormData) {\n // Skip deduplication for FormData\n return undefined\n }\n // Skip deduplication for ReadableStream\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return undefined\n }\n if (typeof body === 'string') {\n bodyString = body\n } else if (body instanceof URLSearchParams) {\n bodyString = body.toString()\n } else if (body instanceof ArrayBuffer) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Uint8Array) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Blob) {\n bodyString = `[blob:${body.type}:${body.size}]`\n } else if (body == null) {\n bodyString = ''\n } else {\n try {\n bodyString = JSON.stringify(body)\n } catch {\n bodyString = '[unserializable-body]'\n }\n }\n return `${method.toUpperCase()}|${url}|${bodyString}`\n}\n"],"mappings":"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","names":[]}
|
package/dist/plugins/dedupe.js
CHANGED
|
@@ -83,45 +83,30 @@ function dedupePlugin(options = {}) {
|
|
|
83
83
|
}
|
|
84
84
|
const existing = inFlight.get(key);
|
|
85
85
|
if (existing) {
|
|
86
|
-
return
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
existing.waiters.push({ resolve, reject });
|
|
88
|
+
});
|
|
87
89
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
let rejectFn;
|
|
91
|
-
const placeholder = new Promise((resolve, reject) => {
|
|
92
|
-
resolveFn = (value) => {
|
|
93
|
-
if (!settled) {
|
|
94
|
-
settled = true;
|
|
95
|
-
resolve(value);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
rejectFn = (reason) => {
|
|
99
|
-
if (!settled) {
|
|
100
|
-
settled = true;
|
|
101
|
-
reject(reason);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
});
|
|
105
|
-
placeholder.catch(() => void 0);
|
|
90
|
+
const waiters = [];
|
|
91
|
+
const actualPromise = next(ctx);
|
|
106
92
|
inFlight.set(key, {
|
|
107
|
-
promise:
|
|
108
|
-
|
|
109
|
-
reject: rejectFn,
|
|
93
|
+
promise: actualPromise,
|
|
94
|
+
waiters,
|
|
110
95
|
createdAt: Date.now()
|
|
111
96
|
});
|
|
112
97
|
startSweeper();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
98
|
+
actualPromise.then(
|
|
99
|
+
(result) => {
|
|
100
|
+
for (const waiter of waiters) {
|
|
101
|
+
waiter.resolve(result.clone());
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
(error) => {
|
|
105
|
+
for (const waiter of waiters) {
|
|
106
|
+
waiter.reject(error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
);
|
|
125
110
|
return actualPromise.finally(() => {
|
|
126
111
|
const current = inFlight.get(key);
|
|
127
112
|
if (current?.promise === actualPromise) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dedupeRequestHash.ts","../../src/plugins/dedupe.ts"],"sourcesContent":["export type DedupeHashParams = {\n method: string\n url: string\n body:\n | string\n | FormData\n | URLSearchParams\n | Blob\n | ArrayBuffer\n | BufferSource\n | null\n | ReadableStream<unknown>\n headers?: Headers | Record<string, string>\n signal?: AbortSignal\n requestInit?: RequestInit\n request?: Request\n}\n\nexport function dedupeRequestHash(\n params: DedupeHashParams\n): string | undefined {\n const { method, url, body } = params\n let bodyString = ''\n if (body instanceof FormData) {\n // Skip deduplication for FormData\n return undefined\n }\n // Skip deduplication for ReadableStream\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return undefined\n }\n if (typeof body === 'string') {\n bodyString = body\n } else if (body instanceof URLSearchParams) {\n bodyString = body.toString()\n } else if (body instanceof ArrayBuffer) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Uint8Array) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Blob) {\n bodyString = `[blob:${body.type}:${body.size}]`\n } else if (body == null) {\n bodyString = ''\n } else {\n try {\n bodyString = JSON.stringify(body)\n } catch {\n bodyString = '[unserializable-body]'\n }\n }\n return `${method.toUpperCase()}|${url}|${bodyString}`\n}\n","import type { ClientPlugin, PluginRequestContext } from '../plugins.js'\nimport {\n dedupeRequestHash,\n type DedupeHashParams,\n} from '../dedupeRequestHash.js'\n\ntype
|
|
1
|
+
{"version":3,"sources":["../../src/dedupeRequestHash.ts","../../src/plugins/dedupe.ts"],"sourcesContent":["export type DedupeHashParams = {\n method: string\n url: string\n body:\n | string\n | FormData\n | URLSearchParams\n | Blob\n | ArrayBuffer\n | BufferSource\n | null\n | ReadableStream<unknown>\n headers?: Headers | Record<string, string>\n signal?: AbortSignal\n requestInit?: RequestInit\n request?: Request\n}\n\nexport function dedupeRequestHash(\n params: DedupeHashParams\n): string | undefined {\n const { method, url, body } = params\n let bodyString = ''\n if (body instanceof FormData) {\n // Skip deduplication for FormData\n return undefined\n }\n // Skip deduplication for ReadableStream\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return undefined\n }\n if (typeof body === 'string') {\n bodyString = body\n } else if (body instanceof URLSearchParams) {\n bodyString = body.toString()\n } else if (body instanceof ArrayBuffer) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Uint8Array) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Blob) {\n bodyString = `[blob:${body.type}:${body.size}]`\n } else if (body == null) {\n bodyString = ''\n } else {\n try {\n bodyString = JSON.stringify(body)\n } catch {\n bodyString = '[unserializable-body]'\n }\n }\n return `${method.toUpperCase()}|${url}|${bodyString}`\n}\n","import type { ClientPlugin, PluginRequestContext } from '../plugins.js'\nimport {\n dedupeRequestHash,\n type DedupeHashParams,\n} from '../dedupeRequestHash.js'\n\ntype Waiter = {\n resolve: (value: Response) => void\n reject: (reason?: unknown) => void\n}\n\ntype DedupeEntry = {\n promise: Promise<Response>\n waiters: Waiter[]\n createdAt: number\n}\n\nexport type DedupePluginOptions = {\n hashFn?: (params: DedupeHashParams) => string | undefined\n ttl?: number\n sweepInterval?: number\n order?: number\n}\n\nfunction contextToHashParams(ctx: PluginRequestContext): DedupeHashParams {\n return {\n method: ctx.request.method,\n url: ctx.request.url,\n body: (ctx.init.body ?? null) as DedupeHashParams['body'],\n headers: ctx.request.headers,\n signal:\n ctx.init.signal === undefined || ctx.init.signal === null\n ? undefined\n : ctx.init.signal,\n requestInit: ctx.init,\n request: ctx.request,\n }\n}\n\nexport function dedupePlugin(options: DedupePluginOptions = {}): ClientPlugin {\n const {\n hashFn = dedupeRequestHash,\n ttl,\n sweepInterval = 5000,\n order = 10,\n } = options\n\n const inFlight = new Map<string, DedupeEntry>()\n let sweeper: ReturnType<typeof setInterval> | undefined\n\n function startSweeper() {\n if (sweeper || typeof ttl !== 'number' || ttl <= 0) return\n sweeper = setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of inFlight.entries()) {\n if (now - entry.createdAt > ttl) {\n inFlight.delete(key)\n }\n }\n if (inFlight.size === 0 && sweeper) {\n clearInterval(sweeper)\n sweeper = undefined\n }\n }, sweepInterval)\n }\n\n function stopSweeperIfIdle() {\n if (inFlight.size === 0 && sweeper) {\n clearInterval(sweeper)\n sweeper = undefined\n }\n }\n\n return {\n name: 'dedupe',\n order,\n wrapDispatch: (next) => async (ctx) => {\n const key = hashFn(contextToHashParams(ctx))\n ctx.state.dedupeKey = key\n\n if (!key) {\n return next(ctx)\n }\n\n const existing = inFlight.get(key)\n if (existing) {\n return new Promise<Response>((resolve, reject) => {\n existing.waiters.push({ resolve, reject })\n })\n }\n\n const waiters: Waiter[] = []\n const actualPromise = next(ctx)\n\n inFlight.set(key, {\n promise: actualPromise,\n waiters,\n createdAt: Date.now(),\n })\n startSweeper()\n\n actualPromise.then(\n (result) => {\n for (const waiter of waiters) {\n waiter.resolve(result.clone())\n }\n },\n (error) => {\n for (const waiter of waiters) {\n waiter.reject(error)\n }\n }\n )\n\n return actualPromise.finally(() => {\n const current = inFlight.get(key)\n if (current?.promise === actualPromise) {\n inFlight.delete(key)\n stopSweeperIfIdle()\n }\n })\n },\n }\n}\n\nexport { dedupeRequestHash }\nexport type { DedupeHashParams }\n"],"mappings":"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","names":[]}
|