Skip to content

Commit 5ad27eb

Browse files
feat: use new API endpoints (#147)
1 parent fc37f3a commit 5ad27eb

File tree

5 files changed

+45
-47
lines changed

5 files changed

+45
-47
lines changed

src/client.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,12 @@ export class Client {
9797
}
9898

9999
const apiHeaders: Record<string, string> = { authorization: `Bearer ${this.token}` }
100-
const url = new URL(`/api/v1/sites/${this.siteID}/blobs`, this.apiURL ?? 'https://api.netlify.com')
100+
const url = new URL(`/api/v1/blobs/${this.siteID}/${storeName}`, this.apiURL ?? 'https://api.netlify.com')
101101

102102
for (const key in parameters) {
103103
url.searchParams.set(key, parameters[key])
104104
}
105105

106-
url.searchParams.set('context', storeName)
107-
108106
// If there is no key, we're dealing with the list endpoint, which is
109107
// implemented directly in the Netlify API.
110108
if (key === undefined) {

src/list.test.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ describe('list', () => {
5959
next_cursor: 'cursor_1',
6060
}),
6161
),
62-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?context=${storeName}`,
62+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}`,
6363
})
6464
.get({
6565
headers: { authorization: `Bearer ${apiToken}` },
@@ -83,7 +83,7 @@ describe('list', () => {
8383
next_cursor: 'cursor_2',
8484
}),
8585
),
86-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_1&context=${storeName}`,
86+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_1`,
8787
})
8888
.get({
8989
headers: { authorization: `Bearer ${apiToken}` },
@@ -100,7 +100,7 @@ describe('list', () => {
100100
directories: [],
101101
}),
102102
),
103-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_2&context=${storeName}`,
103+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_2`,
104104
})
105105

106106
globalThis.fetch = mockStore.fetch
@@ -148,7 +148,7 @@ describe('list', () => {
148148
next_cursor: 'cursor_1',
149149
}),
150150
),
151-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&context=${storeName}`,
151+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true`,
152152
})
153153
.get({
154154
headers: { authorization: `Bearer ${apiToken}` },
@@ -172,7 +172,7 @@ describe('list', () => {
172172
next_cursor: 'cursor_2',
173173
}),
174174
),
175-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&cursor=cursor_1&context=${storeName}`,
175+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_1`,
176176
})
177177
.get({
178178
headers: { authorization: `Bearer ${apiToken}` },
@@ -189,7 +189,7 @@ describe('list', () => {
189189
directories: ['dir3'],
190190
}),
191191
),
192-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&cursor=cursor_2&context=${storeName}`,
192+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_2`,
193193
})
194194
.get({
195195
headers: { authorization: `Bearer ${apiToken}` },
@@ -206,7 +206,7 @@ describe('list', () => {
206206
directories: [],
207207
}),
208208
),
209-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?prefix=dir2%2F&directories=true&context=${storeName}`,
209+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?prefix=dir2%2F&directories=true`,
210210
})
211211

212212
globalThis.fetch = mockStore.fetch
@@ -258,7 +258,7 @@ describe('list', () => {
258258
],
259259
}),
260260
),
261-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?prefix=group%2F&context=${storeName}`,
261+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?prefix=group%2F`,
262262
})
263263

264264
globalThis.fetch = mockStore.fetch
@@ -303,7 +303,7 @@ describe('list', () => {
303303
next_cursor: 'cursor_2',
304304
}),
305305
),
306-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?context=${storeName}`,
306+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}`,
307307
})
308308
.get({
309309
headers: { authorization: `Bearer ${apiToken}` },
@@ -319,7 +319,7 @@ describe('list', () => {
319319
],
320320
}),
321321
),
322-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_2&context=${storeName}`,
322+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_2`,
323323
})
324324

325325
globalThis.fetch = mockStore.fetch

src/main.test.ts

+29-29
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('get', () => {
4747
.get({
4848
headers: { authorization: `Bearer ${apiToken}` },
4949
response: new Response(JSON.stringify({ url: signedURL })),
50-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
50+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
5151
})
5252
.get({
5353
response: new Response(value),
@@ -56,7 +56,7 @@ describe('get', () => {
5656
.get({
5757
headers: { authorization: `Bearer ${apiToken}` },
5858
response: new Response(JSON.stringify({ url: signedURL })),
59-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
59+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
6060
})
6161
.get({
6262
response: new Response(value),
@@ -65,7 +65,7 @@ describe('get', () => {
6565
.get({
6666
headers: { authorization: `Bearer ${apiToken}` },
6767
response: new Response(JSON.stringify({ url: signedURL })),
68-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
68+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
6969
})
7070
.get({
7171
response: new Response(value),
@@ -97,7 +97,7 @@ describe('get', () => {
9797
.get({
9898
headers: { authorization: `Bearer ${apiToken}` },
9999
response: new Response(JSON.stringify({ url: signedURL })),
100-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
100+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
101101
})
102102
.get({
103103
response: new Response('Something went wrong', { status: 404 }),
@@ -120,7 +120,7 @@ describe('get', () => {
120120
const mockStore = new MockFetch().get({
121121
headers: { authorization: `Bearer ${apiToken}` },
122122
response: new Response(null, { status: 401 }),
123-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
123+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
124124
})
125125

126126
globalThis.fetch = mockStore.fetch
@@ -142,7 +142,7 @@ describe('get', () => {
142142
.get({
143143
headers: { authorization: `Bearer ${apiToken}` },
144144
response: new Response(JSON.stringify({ url: signedURL })),
145-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
145+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
146146
})
147147
.get({
148148
response: new Response('Something went wrong', { status: 401 }),
@@ -361,7 +361,7 @@ describe('getMetadata', () => {
361361
const mockStore = new MockFetch().head({
362362
headers: { authorization: `Bearer ${apiToken}` },
363363
response: new Response(null, { headers }),
364-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
364+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
365365
})
366366

367367
globalThis.fetch = mockStore.fetch
@@ -383,7 +383,7 @@ describe('getMetadata', () => {
383383
const mockStore = new MockFetch().head({
384384
headers: { authorization: `Bearer ${apiToken}` },
385385
response: new Response(null, { status: 404 }),
386-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
386+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
387387
})
388388

389389
globalThis.fetch = mockStore.fetch
@@ -406,7 +406,7 @@ describe('getMetadata', () => {
406406
const mockStore = new MockFetch().head({
407407
headers: { authorization: `Bearer ${apiToken}` },
408408
response: new Response(null, { headers }),
409-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
409+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
410410
})
411411

412412
globalThis.fetch = mockStore.fetch
@@ -476,7 +476,7 @@ describe('getWithMetadata', () => {
476476
.get({
477477
headers: { authorization: `Bearer ${apiToken}` },
478478
response: new Response(JSON.stringify({ url: signedURL })),
479-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
479+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
480480
})
481481
.get({
482482
response: new Response(value, { headers: responseHeaders }),
@@ -485,7 +485,7 @@ describe('getWithMetadata', () => {
485485
.get({
486486
headers: { authorization: `Bearer ${apiToken}` },
487487
response: new Response(JSON.stringify({ url: signedURL })),
488-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
488+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
489489
})
490490
.get({
491491
response: new Response(value, { headers: responseHeaders }),
@@ -518,7 +518,7 @@ describe('getWithMetadata', () => {
518518
.get({
519519
headers: { authorization: `Bearer ${apiToken}` },
520520
response: new Response(JSON.stringify({ url: signedURL })),
521-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
521+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
522522
})
523523
.get({
524524
response: new Response('Something went wrong', { status: 404 }),
@@ -546,7 +546,7 @@ describe('getWithMetadata', () => {
546546
.get({
547547
headers: { authorization: `Bearer ${apiToken}` },
548548
response: new Response(JSON.stringify({ url: signedURL })),
549-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
549+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
550550
})
551551
.get({
552552
response: new Response(value, { headers: responseHeaders }),
@@ -585,7 +585,7 @@ describe('getWithMetadata', () => {
585585
.get({
586586
headers: { authorization: `Bearer ${apiToken}` },
587587
response: new Response(JSON.stringify({ url: `${signedURL}b` })),
588-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
588+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
589589
})
590590
.get({
591591
headers: { 'if-none-match': etags.wrong },
@@ -595,7 +595,7 @@ describe('getWithMetadata', () => {
595595
.get({
596596
headers: { authorization: `Bearer ${apiToken}` },
597597
response: new Response(JSON.stringify({ url: `${signedURL}a` })),
598-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
598+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
599599
})
600600
.get({
601601
headers: { 'if-none-match': etags.right },
@@ -679,7 +679,7 @@ describe('set', () => {
679679
.put({
680680
headers: { authorization: `Bearer ${apiToken}` },
681681
response: new Response(JSON.stringify({ url: signedURL })),
682-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
682+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
683683
})
684684
.put({
685685
body: value,
@@ -690,7 +690,7 @@ describe('set', () => {
690690
.put({
691691
headers: { authorization: `Bearer ${apiToken}` },
692692
response: new Response(JSON.stringify({ url: signedURL })),
693-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
693+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
694694
})
695695
.put({
696696
body: value,
@@ -724,7 +724,7 @@ describe('set', () => {
724724
.put({
725725
headers: { authorization: `Bearer ${apiToken}`, 'netlify-blobs-metadata': encodedMetadata },
726726
response: new Response(JSON.stringify({ url: signedURL })),
727-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
727+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
728728
})
729729
.put({
730730
body: value,
@@ -753,7 +753,7 @@ describe('set', () => {
753753
const mockStore = new MockFetch().put({
754754
headers: { authorization: `Bearer ${apiToken}` },
755755
response: new Response(null, { status: 401 }),
756-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
756+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
757757
})
758758

759759
globalThis.fetch = mockStore.fetch
@@ -795,7 +795,7 @@ describe('set', () => {
795795
.put({
796796
headers: { authorization: `Bearer ${apiToken}` },
797797
response: new Response(JSON.stringify({ url: signedURL })),
798-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
798+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
799799
})
800800
.put({
801801
body: value,
@@ -949,7 +949,7 @@ describe('setJSON', () => {
949949
.put({
950950
headers: { authorization: `Bearer ${apiToken}` },
951951
response: new Response(JSON.stringify({ url: signedURL })),
952-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
952+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
953953
})
954954
.put({
955955
body: JSON.stringify({ value }),
@@ -1058,7 +1058,7 @@ describe('delete', () => {
10581058
.delete({
10591059
headers: { authorization: `Bearer ${apiToken}` },
10601060
response: new Response(JSON.stringify({ url: signedURL })),
1061-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
1061+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
10621062
})
10631063
.delete({
10641064
response: new Response(null),
@@ -1067,7 +1067,7 @@ describe('delete', () => {
10671067
.delete({
10681068
headers: { authorization: `Bearer ${apiToken}` },
10691069
response: new Response(JSON.stringify({ url: signedURL })),
1070-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
1070+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
10711071
})
10721072
.delete({
10731073
response: new Response(null),
@@ -1093,7 +1093,7 @@ describe('delete', () => {
10931093
.delete({
10941094
headers: { authorization: `Bearer ${apiToken}` },
10951095
response: new Response(JSON.stringify({ url: signedURL })),
1096-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
1096+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
10971097
})
10981098
.delete({
10991099
response: new Response(null, { status: 404 }),
@@ -1117,7 +1117,7 @@ describe('delete', () => {
11171117
const mockStore = new MockFetch().delete({
11181118
headers: { authorization: `Bearer ${apiToken}` },
11191119
response: new Response(null, { status: 401 }),
1120-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
1120+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
11211121
})
11221122

11231123
globalThis.fetch = mockStore.fetch
@@ -1244,7 +1244,7 @@ describe('Deploy scope', () => {
12441244
.get({
12451245
headers: { authorization: `Bearer ${apiToken}` },
12461246
response: new Response(JSON.stringify({ url: signedURL })),
1247-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
1247+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
12481248
})
12491249
.get({
12501250
response: new Response(value),
@@ -1253,7 +1253,7 @@ describe('Deploy scope', () => {
12531253
.get({
12541254
headers: { authorization: `Bearer ${apiToken}` },
12551255
response: new Response(JSON.stringify({ url: signedURL })),
1256-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
1256+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
12571257
})
12581258
.get({
12591259
response: new Response(value),
@@ -1314,7 +1314,7 @@ describe('Deploy scope', () => {
13141314
.get({
13151315
headers: { authorization: `Bearer ${apiToken}` },
13161316
response: new Response(JSON.stringify({ url: signedURL })),
1317-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
1317+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
13181318
})
13191319
.get({
13201320
response: new Response(value),
@@ -1323,7 +1323,7 @@ describe('Deploy scope', () => {
13231323
.get({
13241324
headers: { authorization: `Bearer ${apiToken}` },
13251325
response: new Response(JSON.stringify({ url: signedURL })),
1326-
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
1326+
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
13271327
})
13281328
.get({
13291329
response: new Response(value),

src/retry.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { env } from 'node:process'
2+
13
import type { Fetcher } from './types.ts'
24

3-
const DEFAULT_RETRY_DELAY = 5000
5+
const DEFAULT_RETRY_DELAY = env.NODE_ENV === 'test' ? 1 : 5000
46
const MIN_RETRY_DELAY = 1000
57
const MAX_RETRY = 5
68
const RATE_LIMIT_HEADER = 'X-RateLimit-Reset'

src/server.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import { decodeMetadata, encodeMetadata, METADATA_HEADER_INTERNAL } from './meta
1212
import { HTTPMethod } from './types.ts'
1313
import { isNodeError, Logger } from './util.ts'
1414

15-
const API_URL_PATH = /\/api\/v1\/sites\/(?<site_id>[^/]+)\/blobs\/?(?<key>[^?]*)/
16-
const DEFAULT_STORE = 'production'
15+
const API_URL_PATH = /\/api\/v1\/blobs\/(?<site_id>[^/]+)\/(?<store_name>[^/]+)\/?(?<key>[^?]*)/
1716

1817
export enum Operation {
1918
DELETE = 'delete',
@@ -367,10 +366,9 @@ export class BlobsServer {
367366
return null
368367
}
369368

370-
const fullURL = new URL(req.url, this.address)
371-
const storeName = fullURL.searchParams.get('context') ?? DEFAULT_STORE
372369
const key = apiURLMatch.groups?.key
373370
const siteID = apiURLMatch.groups?.site_id as string
371+
const storeName = apiURLMatch.groups?.store_name as string
374372
const urlPath = [siteID, storeName, key].filter(Boolean) as string[]
375373
const url = new URL(`/${urlPath.join('/')}?signature=${this.tokenHash}`, this.address)
376374

0 commit comments

Comments
 (0)