@apicity/free-media-upload 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +353 -0
- package/dist/src/example.d.ts +8 -0
- package/dist/src/example.d.ts.map +1 -0
- package/dist/src/example.js +85 -0
- package/dist/src/example.js.map +1 -0
- package/dist/src/freeMediaUpload.d.ts +3 -0
- package/dist/src/freeMediaUpload.d.ts.map +1 -0
- package/dist/src/freeMediaUpload.js +239 -0
- package/dist/src/freeMediaUpload.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/middleware.d.ts +34 -0
- package/dist/src/middleware.d.ts.map +1 -0
- package/dist/src/middleware.js +219 -0
- package/dist/src/middleware.js.map +1 -0
- package/dist/src/sse.d.ts +6 -0
- package/dist/src/sse.d.ts.map +1 -0
- package/dist/src/sse.js +55 -0
- package/dist/src/sse.js.map +1 -0
- package/dist/src/types.d.ts +150 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +15 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/uploadToAnyHost.d.ts +10 -0
- package/dist/src/uploadToAnyHost.d.ts.map +1 -0
- package/dist/src/uploadToAnyHost.js +44 -0
- package/dist/src/uploadToAnyHost.js.map +1 -0
- package/dist/src/zod.d.ts +107 -0
- package/dist/src/zod.d.ts.map +1 -0
- package/dist/src/zod.js +70 -0
- package/dist/src/zod.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Justin Tanner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# @apicity/free-media-upload
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@apicity/free-media-upload)
|
|
4
|
+
[](package.json)
|
|
5
|
+
[](tsconfig.json)
|
|
6
|
+
|
|
7
|
+
Zero-auth file hosting wrapper for catbox, gofile, uguu, filebin, litterbox, tempsh, tflink, and tmpfiles — eight providers behind one typed surface.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @apicity/free-media-upload
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @apicity/free-media-upload
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { freeMediaUpload as createFreeMediaUpload } from "@apicity/free-media-upload";
|
|
21
|
+
|
|
22
|
+
const freeMediaUpload = createFreeMediaUpload({ apiKey: process.env.FREE-MEDIA-UPLOAD_API_KEY! });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Real-world example: race a portrait across four free hosts
|
|
26
|
+
|
|
27
|
+
`@apicity/free-media-upload` wraps eight zero-auth, no-account file-hosting endpoints
|
|
28
|
+
behind one typed surface — the win is being able to fan the same `Blob`
|
|
29
|
+
out to multiple hosts in parallel, then pick whichever URL came back
|
|
30
|
+
first (or any survivor) without rewriting four different multipart
|
|
31
|
+
callers. The snippet below uploads a single 84 KB JPEG to the four
|
|
32
|
+
richest response shapes — catbox (plain string), gofile (rich bundle
|
|
33
|
+
metadata), uguu (random-rename + dupe detection), filebin (md5/sha256 +
|
|
34
|
+
expiry) — and shows how to normalise them under one `toUrl()` helper.
|
|
35
|
+
|
|
36
|
+
Every URL, byte count, and hash below is mined verbatim from
|
|
37
|
+
[`tests/recordings/free_2578706139/`](../../../tests/recordings/free_2578706139/),
|
|
38
|
+
replayed by
|
|
39
|
+
[`tests/integration/free-catbox.test.ts`](../../../tests/integration/free-catbox.test.ts),
|
|
40
|
+
[`tests/integration/free-gofile.test.ts`](../../../tests/integration/free-gofile.test.ts),
|
|
41
|
+
[`tests/integration/free-uguu.test.ts`](../../../tests/integration/free-uguu.test.ts),
|
|
42
|
+
[`tests/integration/free-filebin.test.ts`](../../../tests/integration/free-filebin.test.ts),
|
|
43
|
+
and [`tests/integration/free-litterbox.test.ts`](../../../tests/integration/free-litterbox.test.ts).
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { readFileSync } from "node:fs";
|
|
47
|
+
import { freeMediaUpload as createFreeMediaUpload } from "@apicity/free-media-upload";
|
|
48
|
+
import type { GofileUploadResponse, UguuUploadResponse, FilebinUploadResponse } from "@apicity/free-media-upload";
|
|
49
|
+
|
|
50
|
+
// 1. The factory takes no api key — every host below is genuinely
|
|
51
|
+
// auth-free and account-free. Pass `{ timeout: 60_000 }` or a
|
|
52
|
+
// custom `fetch` if you need to override the defaults.
|
|
53
|
+
const freeMediaUpload = createFreeMediaUpload();
|
|
54
|
+
|
|
55
|
+
const bytes = readFileSync("./cat1.jpg"); // 83,558 bytes
|
|
56
|
+
const file = new Blob([bytes], { type: "image/jpeg" });
|
|
57
|
+
|
|
58
|
+
// 2. Race four hosts in parallel via Promise.all. Each returns a
|
|
59
|
+
// different shape: catbox/litterbox/tempsh hand back a plain
|
|
60
|
+
// `string` URL, gofile/tflink return a metadata bundle, uguu's
|
|
61
|
+
// payload nests under `files[]`, and filebin splits things into
|
|
62
|
+
// `bin` + `file` blocks. The factory keeps these distinctions in
|
|
63
|
+
// the type system so the destructure below is statically checked.
|
|
64
|
+
const [catboxUrl, gofile, uguu, filebin] = (await Promise.all([
|
|
65
|
+
free.catbox.upload({ file, filename: "cat1.jpg" }),
|
|
66
|
+
free.gofile.upload({ file, filename: "cat1.jpg" }),
|
|
67
|
+
free.uguu.upload({ file, filename: "cat1.jpg" }),
|
|
68
|
+
free.filebin.upload({ file, filename: "cat1.jpg", bin: "apicity-test-img" }),
|
|
69
|
+
])) as [string, GofileUploadResponse, UguuUploadResponse, FilebinUploadResponse];
|
|
70
|
+
|
|
71
|
+
// 3. catbox is the simplest UX: text/plain response, just the URL,
|
|
72
|
+
// permanent until the operator deletes it. Good for a 'host once,
|
|
73
|
+
// forget' public asset.
|
|
74
|
+
console.log(catboxUrl);
|
|
75
|
+
// → "https://files.catbox.moe/0ufdor.jpg"
|
|
76
|
+
|
|
77
|
+
// 4. gofile is the only host that gives you a sharable download page
|
|
78
|
+
// (suitable for human consumption) plus a CDN-direct id you can use
|
|
79
|
+
// to build APIs against. The `parentFolderCode` is a 6-char folder
|
|
80
|
+
// handle — every upload lands in a fresh anonymous folder unless
|
|
81
|
+
// you authenticate.
|
|
82
|
+
console.log(gofile.data.downloadPage);
|
|
83
|
+
// → "https://gofile.io/d/hmoMxW"
|
|
84
|
+
console.log(gofile.data.id, gofile.data.md5, gofile.data.size);
|
|
85
|
+
// → "a7feccb4-96b4-4b2c-923a-832106388ad6" "391a26048ce697ba072acd83209923f7" 83558
|
|
86
|
+
|
|
87
|
+
// 5. uguu rewrites filenames to a random 8-char slug to stop URL
|
|
88
|
+
// enumeration, and tells you whether your bytes were already on
|
|
89
|
+
// the host (`dupe: true`) so you can skip a re-upload next time.
|
|
90
|
+
// Note the `files[]` array — uguu accepts batched uploads via the
|
|
91
|
+
// same endpoint, even though @apicity/free-media-upload only ships single-file.
|
|
92
|
+
console.log(uguu.files[0].url, uguu.files[0].dupe);
|
|
93
|
+
// → "https://n.uguu.se/GeNMsbBp.jpg" false
|
|
94
|
+
|
|
95
|
+
// 6. filebin verifies content integrity for you — it returns both
|
|
96
|
+
// md5 and sha256, plus an expiry. The `bin` is a namespace you can
|
|
97
|
+
// re-upload into to grow a multi-file bundle (omit `bin` and you
|
|
98
|
+
// get an auto-generated one). Files in a bin expire together on
|
|
99
|
+
// `bin.expired_at`.
|
|
100
|
+
console.log(filebin.file.md5, filebin.file.sha256);
|
|
101
|
+
// → "ORomBIzml7oHKs2DIJkj9w==" "561dbe5dcd0c931cd3b41705ebe00df9181560967cea8b17128373a06ab911a3"
|
|
102
|
+
console.log(`bin "${filebin.bin.id}" expires ${filebin.bin.expired_at}`);
|
|
103
|
+
// → 'bin "apicity-test-img" expires 2026-04-23T07:19:25.458442Z'
|
|
104
|
+
|
|
105
|
+
// 7. Hosts that return strings already give you a URL; hosts that
|
|
106
|
+
// return JSON bury it under different keys. A tiny normaliser lets
|
|
107
|
+
// downstream code stop caring which host won the race.
|
|
108
|
+
function toUrl(
|
|
109
|
+
res: string | GofileUploadResponse | UguuUploadResponse | FilebinUploadResponse,
|
|
110
|
+
bin?: string,
|
|
111
|
+
filename?: string,
|
|
112
|
+
): string {
|
|
113
|
+
if (typeof res === "string") return res;
|
|
114
|
+
if ("data" in res) return res.data.downloadPage; // gofile
|
|
115
|
+
if ("files" in res) return res.files[0].url; // uguu
|
|
116
|
+
return `https://filebin.net/${bin}/${filename}`; // filebin
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log([
|
|
120
|
+
toUrl(catboxUrl),
|
|
121
|
+
toUrl(gofile),
|
|
122
|
+
toUrl(uguu),
|
|
123
|
+
toUrl(filebin, "apicity-test-img", "cat1.jpg"),
|
|
124
|
+
]);
|
|
125
|
+
// → [
|
|
126
|
+
// "https://files.catbox.moe/0ufdor.jpg",
|
|
127
|
+
// "https://gofile.io/d/hmoMxW",
|
|
128
|
+
// "https://n.uguu.se/GeNMsbBp.jpg",
|
|
129
|
+
// "https://filebin.net/apicity-test-img/cat1.jpg",
|
|
130
|
+
// ]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Failover across ephemeral hosts
|
|
134
|
+
|
|
135
|
+
When you only need a URL to live for a few hours — typically because a
|
|
136
|
+
downstream model is about to GET it once and then forget — `@apicity/free-media-upload`
|
|
137
|
+
ships a `uploadToAnyHost` helper that walks a randomised host list and
|
|
138
|
+
returns the first successful URL, raising a single `FreeMediaUploadError` only if
|
|
139
|
+
every host fails. Useful when one provider is flaky (uguu's CDN can 502
|
|
140
|
+
during traffic spikes) but you don't care which one wins.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { freeMediaUpload as createFreeMediaUpload, uploadToAnyHost, FreeMediaUploadError } from "@apicity/free-media-upload";
|
|
144
|
+
|
|
145
|
+
const freeMediaUpload = createFreeMediaUpload();
|
|
146
|
+
const file = new Blob([bytes], { type: "image/jpeg" });
|
|
147
|
+
|
|
148
|
+
// litterbox accepts a TTL; uguu and tflink are best-effort permanent.
|
|
149
|
+
// uploadToAnyHost shuffles the list and tries each host sequentially,
|
|
150
|
+
// so a single 502 from uguu falls through to tflink without your code
|
|
151
|
+
// ever seeing it. The returned URL is already normalised — string in,
|
|
152
|
+
// string out, regardless of which host responded.
|
|
153
|
+
try {
|
|
154
|
+
const url = await uploadToAnyHost(free, {
|
|
155
|
+
file,
|
|
156
|
+
filename: "cat1.jpg",
|
|
157
|
+
hosts: ["litterbox", "uguu", "tflink"],
|
|
158
|
+
time: "12h", // forwarded to litterbox if it wins the shuffle
|
|
159
|
+
});
|
|
160
|
+
console.log(url);
|
|
161
|
+
// → "https://litter.catbox.moe/04obtk.jpg" // example: litterbox won
|
|
162
|
+
} catch (err) {
|
|
163
|
+
if (err instanceof FreeMediaUploadError) {
|
|
164
|
+
// err.body.failures is a string[] of `<host>: <message>` lines —
|
|
165
|
+
// useful for surfacing exactly which hosts misbehaved.
|
|
166
|
+
console.error(err.status, err.body);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Notes**
|
|
172
|
+
|
|
173
|
+
- All eight endpoints take `{ file: Blob, filename?: string }`. catbox
|
|
174
|
+
and litterbox respond with `text/plain` (the URL itself); tmpfiles,
|
|
175
|
+
uguu, gofile, filebin, and tflink return JSON; tempsh returns plain
|
|
176
|
+
text. The factory parses each correctly so you never see the raw
|
|
177
|
+
body — just the typed shape.
|
|
178
|
+
- `litterbox.upload` is the only endpoint with a `time` field —
|
|
179
|
+
`"1h" | "12h" | "24h" | "72h"`. Anything longer than 72h needs the
|
|
180
|
+
permanent-host siblings (catbox, gofile, filebin).
|
|
181
|
+
- `filebin.upload` is the odd one out: it's a binary `POST` (no
|
|
182
|
+
multipart wrapper), so the `Blob` goes on the wire as-is and the
|
|
183
|
+
server treats `<bin>/<filename>` as the upload target. Re-uploading
|
|
184
|
+
to the same `bin` adds the file to the bundle rather than replacing
|
|
185
|
+
it; pre-create a stable `bin` slug to grow a multi-file collection.
|
|
186
|
+
- gofile's `guestToken` is the closest thing this provider has to an
|
|
187
|
+
auth handle — save it if you want to delete the upload later via
|
|
188
|
+
the gofile API. Without it, anonymous uploads are write-only.
|
|
189
|
+
- Every endpoint exposes a Zod schema:
|
|
190
|
+
`free.catbox.upload.schema.safeParse(input)` validates the payload
|
|
191
|
+
before the network call, which catches the most common mistake
|
|
192
|
+
(passing a `Buffer` or `string` instead of a `Blob`).
|
|
193
|
+
- All endpoints accept an `AbortSignal` second argument and compose
|
|
194
|
+
with `withRetry` / `withFallback` from `@apicity/free-media-upload`'s middleware
|
|
195
|
+
re-exports — useful for ride-out 429s on uguu or chaining gofile →
|
|
196
|
+
catbox as a fallback pair.
|
|
197
|
+
- Errors throw `FreeMediaUploadError` with `status` and the parsed body attached:
|
|
198
|
+
`try { ... } catch (e) { if (e instanceof FreeMediaUploadError) console.error(e.status, e.body); }`.
|
|
199
|
+
|
|
200
|
+
## API Reference
|
|
201
|
+
|
|
202
|
+
8 endpoints across 8 groups. Each method mirrors an upstream URL path.
|
|
203
|
+
|
|
204
|
+
### catbox
|
|
205
|
+
|
|
206
|
+
<details>
|
|
207
|
+
<summary><code>POST</code> <b><code>free-media-upload.catbox.upload</code></b></summary>
|
|
208
|
+
|
|
209
|
+
<code>POST https://catbox.moe/user/api.php</code>
|
|
210
|
+
|
|
211
|
+
[Upstream docs ↗](https://catbox.moe/tools.php)
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
const res = await free-media-upload.catbox.upload({ /* ... */ });
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
### filebin
|
|
222
|
+
|
|
223
|
+
<details>
|
|
224
|
+
<summary><code>POST</code> <b><code>free-media-upload.filebin.upload</code></b></summary>
|
|
225
|
+
|
|
226
|
+
<code>POST https://filebin.net/{bin}/{filename}</code>
|
|
227
|
+
|
|
228
|
+
[Upstream docs ↗](https://filebin.net/)
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const res = await free-media-upload.filebin.upload({ /* ... */ });
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
235
|
+
|
|
236
|
+
</details>
|
|
237
|
+
|
|
238
|
+
### gofile
|
|
239
|
+
|
|
240
|
+
<details>
|
|
241
|
+
<summary><code>POST</code> <b><code>free-media-upload.gofile.upload</code></b></summary>
|
|
242
|
+
|
|
243
|
+
<code>POST https://upload.gofile.io/uploadfile</code>
|
|
244
|
+
|
|
245
|
+
[Upstream docs ↗](https://gofile.io/api)
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const res = await free-media-upload.gofile.upload({ /* ... */ });
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
252
|
+
|
|
253
|
+
</details>
|
|
254
|
+
|
|
255
|
+
### litterbox
|
|
256
|
+
|
|
257
|
+
<details>
|
|
258
|
+
<summary><code>POST</code> <b><code>free-media-upload.litterbox.upload</code></b></summary>
|
|
259
|
+
|
|
260
|
+
<code>POST https://litterbox.catbox.moe/resources/internals/api.php</code>
|
|
261
|
+
|
|
262
|
+
[Upstream docs ↗](https://litterbox.catbox.moe/)
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const res = await free-media-upload.litterbox.upload({ /* ... */ });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
269
|
+
|
|
270
|
+
</details>
|
|
271
|
+
|
|
272
|
+
### tempsh
|
|
273
|
+
|
|
274
|
+
<details>
|
|
275
|
+
<summary><code>POST</code> <b><code>free-media-upload.tempsh.upload</code></b></summary>
|
|
276
|
+
|
|
277
|
+
<code>POST https://temp.sh/upload</code>
|
|
278
|
+
|
|
279
|
+
[Upstream docs ↗](https://temp.sh/)
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
const res = await free-media-upload.tempsh.upload({ /* ... */ });
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
286
|
+
|
|
287
|
+
</details>
|
|
288
|
+
|
|
289
|
+
### tflink
|
|
290
|
+
|
|
291
|
+
<details>
|
|
292
|
+
<summary><code>POST</code> <b><code>free-media-upload.tflink.upload</code></b></summary>
|
|
293
|
+
|
|
294
|
+
<code>POST https://tmpfile.link/api/upload</code>
|
|
295
|
+
|
|
296
|
+
[Upstream docs ↗](https://tmpfile.link/)
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
const res = await free-media-upload.tflink.upload({ /* ... */ });
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
303
|
+
|
|
304
|
+
</details>
|
|
305
|
+
|
|
306
|
+
### tmpfiles
|
|
307
|
+
|
|
308
|
+
<details>
|
|
309
|
+
<summary><code>POST</code> <b><code>free-media-upload.tmpfiles.api.v1.upload</code></b></summary>
|
|
310
|
+
|
|
311
|
+
<code>POST https://tmpfiles.org/api/v1/upload</code>
|
|
312
|
+
|
|
313
|
+
[Upstream docs ↗](https://tmpfiles.org/)
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
const res = await free-media-upload.tmpfiles.api.v1.upload({ /* ... */ });
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
320
|
+
|
|
321
|
+
</details>
|
|
322
|
+
|
|
323
|
+
### uguu
|
|
324
|
+
|
|
325
|
+
<details>
|
|
326
|
+
<summary><code>POST</code> <b><code>free-media-upload.uguu.upload</code></b></summary>
|
|
327
|
+
|
|
328
|
+
<code>POST https://uguu.se/upload</code>
|
|
329
|
+
|
|
330
|
+
[Upstream docs ↗](https://uguu.se/)
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
const res = await free-media-upload.uguu.upload({ /* ... */ });
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Source: [`packages/provider/free-media-upload/src/freeMediaUpload.ts`](src/freeMediaUpload.ts)
|
|
337
|
+
|
|
338
|
+
</details>
|
|
339
|
+
|
|
340
|
+
## Middleware
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { freeMediaUpload as createFreeMediaUpload, withRetry } from "@apicity/free-media-upload";
|
|
344
|
+
|
|
345
|
+
const freeMediaUpload = createFreeMediaUpload({ apiKey: process.env.FREE-MEDIA-UPLOAD_API_KEY! });
|
|
346
|
+
const models = withRetry(freeMediaUpload.get.v1.models, { retries: 3 });
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Part of the [apicity](https://github.com/justintanner/apicity) monorepo.
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example.d.ts","sourceRoot":"","sources":["../../src/example.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,QAAA,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAM,CAAC;AAErD,eAAe,QAAQ,CAAC;AAOxB,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CA6ChD"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Auto-generated by `pnpm run gen:examples` — do not edit by hand.
|
|
2
|
+
// Source: tests/recordings/<provider>_*/<test>_*/recording.har
|
|
3
|
+
//
|
|
4
|
+
// Each entry is the green-path payload for one endpoint, mined from a real
|
|
5
|
+
// integration-test recording. `attachExamples` walks the provider tree and
|
|
6
|
+
// hangs the matching entry off each endpoint function as `.example`.
|
|
7
|
+
const EXAMPLES = {};
|
|
8
|
+
export default EXAMPLES;
|
|
9
|
+
// Walks each "<METHOD> <dotPath>" key onto the provider's tree. Tries the
|
|
10
|
+
// standard `provider.<method>.<dotPath>` shape first, then a few fallbacks
|
|
11
|
+
// to cover providers with non-standard layouts (fal's `.run.` namespace,
|
|
12
|
+
// kie's sub-providers, `free`'s flat root). Returns the same provider for
|
|
13
|
+
// drop-in use as `return attachExamples({ ... });`.
|
|
14
|
+
export function attachExamples(provider) {
|
|
15
|
+
const root = provider;
|
|
16
|
+
const HTTP_KEYS = new Set(["post", "get", "put", "delete", "patch", "head"]);
|
|
17
|
+
for (const [key, example] of Object.entries(EXAMPLES)) {
|
|
18
|
+
const sp = key.indexOf(" ");
|
|
19
|
+
if (sp < 0)
|
|
20
|
+
continue;
|
|
21
|
+
const method = key.slice(0, sp).toLowerCase();
|
|
22
|
+
const segs = key.slice(sp + 1).split(".");
|
|
23
|
+
const candidates = [
|
|
24
|
+
root[method],
|
|
25
|
+
root[method]?.run,
|
|
26
|
+
root,
|
|
27
|
+
];
|
|
28
|
+
if (segs.length > 1) {
|
|
29
|
+
const sub = root[segs[0]];
|
|
30
|
+
if (sub && typeof sub === "object") {
|
|
31
|
+
const subMethod = sub[method];
|
|
32
|
+
if (subMethod)
|
|
33
|
+
candidates.push({ __nested: subMethod, __segs: segs.slice(1) });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let attached = false;
|
|
37
|
+
for (const c of candidates) {
|
|
38
|
+
const fn = walkToFn(c, segs);
|
|
39
|
+
if (fn) {
|
|
40
|
+
Object.assign(fn, { example });
|
|
41
|
+
attached = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (attached)
|
|
46
|
+
continue;
|
|
47
|
+
for (const k of Object.keys(root)) {
|
|
48
|
+
if (HTTP_KEYS.has(k))
|
|
49
|
+
continue;
|
|
50
|
+
if (!segs.includes(k))
|
|
51
|
+
continue;
|
|
52
|
+
const sub = root[k];
|
|
53
|
+
if (!sub || typeof sub !== "object")
|
|
54
|
+
continue;
|
|
55
|
+
const subMethod = sub[method];
|
|
56
|
+
if (!subMethod)
|
|
57
|
+
continue;
|
|
58
|
+
const fn = walkToFn(subMethod, segs);
|
|
59
|
+
if (fn) {
|
|
60
|
+
Object.assign(fn, { example });
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return provider;
|
|
66
|
+
}
|
|
67
|
+
function walkToFn(start, segs) {
|
|
68
|
+
if (start && typeof start === "object" && "__nested" in start) {
|
|
69
|
+
const wrapper = start;
|
|
70
|
+
return walkToFn(wrapper.__nested, wrapper.__segs);
|
|
71
|
+
}
|
|
72
|
+
let cur = start;
|
|
73
|
+
for (const seg of segs) {
|
|
74
|
+
if (cur === null || cur === undefined)
|
|
75
|
+
return null;
|
|
76
|
+
const t = typeof cur;
|
|
77
|
+
if (t !== "object" && t !== "function")
|
|
78
|
+
return null;
|
|
79
|
+
cur = cur[seg];
|
|
80
|
+
}
|
|
81
|
+
return typeof cur === "function"
|
|
82
|
+
? cur
|
|
83
|
+
: null;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=example.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example.js","sourceRoot":"","sources":["../../src/example.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freeMediaUpload.d.ts","sourceRoot":"","sources":["../../src/freeMediaUpload.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EActB,uBAAuB,EAExB,MAAM,SAAS,CAAC;AAajB,wBAAgB,eAAe,CAC7B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,uBAAuB,CAmWzB"}
|