Skip to content

Commit

Permalink
feat: use V2 API endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Mar 1, 2024
1 parent fc37f3a commit 83875fd
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 47 deletions.
4 changes: 1 addition & 3 deletions src/client.ts
Expand Up @@ -97,14 +97,12 @@ export class Client {
}

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

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

url.searchParams.set('context', storeName)

// If there is no key, we're dealing with the list endpoint, which is
// implemented directly in the Netlify API.
if (key === undefined) {
Expand Down
20 changes: 10 additions & 10 deletions src/list.test.ts
Expand Up @@ -59,7 +59,7 @@ describe('list', () => {
next_cursor: 'cursor_1',
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -83,7 +83,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_1&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_1`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -100,7 +100,7 @@ describe('list', () => {
directories: [],
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_2&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_2`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -148,7 +148,7 @@ describe('list', () => {
next_cursor: 'cursor_1',
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -172,7 +172,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&cursor=cursor_1&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_1`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -189,7 +189,7 @@ describe('list', () => {
directories: ['dir3'],
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?directories=true&cursor=cursor_2&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_2`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -206,7 +206,7 @@ describe('list', () => {
directories: [],
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?prefix=dir2%2F&directories=true&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?prefix=dir2%2F&directories=true`,
})

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

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -303,7 +303,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -319,7 +319,7 @@ describe('list', () => {
],
}),
),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs?cursor=cursor_2&context=${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_2`,
})

globalThis.fetch = mockStore.fetch
Expand Down
58 changes: 29 additions & 29 deletions src/main.test.ts
Expand Up @@ -47,7 +47,7 @@ describe('get', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response(value),
Expand All @@ -56,7 +56,7 @@ describe('get', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response(value),
Expand All @@ -65,7 +65,7 @@ describe('get', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
})
.get({
response: new Response(value),
Expand Down Expand Up @@ -97,7 +97,7 @@ describe('get', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response('Something went wrong', { status: 404 }),
Expand All @@ -120,7 +120,7 @@ describe('get', () => {
const mockStore = new MockFetch().get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(null, { status: 401 }),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand All @@ -142,7 +142,7 @@ describe('get', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response('Something went wrong', { status: 401 }),
Expand Down Expand Up @@ -361,7 +361,7 @@ describe('getMetadata', () => {
const mockStore = new MockFetch().head({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(null, { headers }),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})

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

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

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -476,7 +476,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response(value, { headers: responseHeaders }),
Expand All @@ -485,7 +485,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response(value, { headers: responseHeaders }),
Expand Down Expand Up @@ -518,7 +518,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response('Something went wrong', { status: 404 }),
Expand Down Expand Up @@ -546,7 +546,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
response: new Response(value, { headers: responseHeaders }),
Expand Down Expand Up @@ -585,7 +585,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: `${signedURL}b` })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
headers: { 'if-none-match': etags.wrong },
Expand All @@ -595,7 +595,7 @@ describe('getWithMetadata', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: `${signedURL}a` })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.get({
headers: { 'if-none-match': etags.right },
Expand Down Expand Up @@ -679,7 +679,7 @@ describe('set', () => {
.put({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.put({
body: value,
Expand All @@ -690,7 +690,7 @@ describe('set', () => {
.put({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
})
.put({
body: value,
Expand Down Expand Up @@ -724,7 +724,7 @@ describe('set', () => {
.put({
headers: { authorization: `Bearer ${apiToken}`, 'netlify-blobs-metadata': encodedMetadata },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.put({
body: value,
Expand Down Expand Up @@ -753,7 +753,7 @@ describe('set', () => {
const mockStore = new MockFetch().put({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(null, { status: 401 }),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -795,7 +795,7 @@ describe('set', () => {
.put({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.put({
body: value,
Expand Down Expand Up @@ -949,7 +949,7 @@ describe('setJSON', () => {
.put({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.put({
body: JSON.stringify({ value }),
Expand Down Expand Up @@ -1058,7 +1058,7 @@ describe('delete', () => {
.delete({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.delete({
response: new Response(null),
Expand All @@ -1067,7 +1067,7 @@ describe('delete', () => {
.delete({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${complexKey}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${complexKey}`,
})
.delete({
response: new Response(null),
Expand All @@ -1093,7 +1093,7 @@ describe('delete', () => {
.delete({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})
.delete({
response: new Response(null, { status: 404 }),
Expand All @@ -1117,7 +1117,7 @@ describe('delete', () => {
const mockStore = new MockFetch().delete({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(null, { status: 401 }),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -1244,7 +1244,7 @@ describe('Deploy scope', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
})
.get({
response: new Response(value),
Expand All @@ -1253,7 +1253,7 @@ describe('Deploy scope', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
})
.get({
response: new Response(value),
Expand Down Expand Up @@ -1314,7 +1314,7 @@ describe('Deploy scope', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
})
.get({
response: new Response(value),
Expand All @@ -1323,7 +1323,7 @@ describe('Deploy scope', () => {
.get({
headers: { authorization: `Bearer ${apiToken}` },
response: new Response(JSON.stringify({ url: signedURL })),
url: `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=deploy%3A${deployID}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/deploy:${deployID}/${key}`,
})
.get({
response: new Response(value),
Expand Down
4 changes: 3 additions & 1 deletion src/retry.ts
@@ -1,6 +1,8 @@
import { env } from 'node:process'

import type { Fetcher } from './types.ts'

const DEFAULT_RETRY_DELAY = 5000
const DEFAULT_RETRY_DELAY = env.NODE_ENV === 'test' ? 1 : 5000
const MIN_RETRY_DELAY = 1000
const MAX_RETRY = 5
const RATE_LIMIT_HEADER = 'X-RateLimit-Reset'
Expand Down
6 changes: 2 additions & 4 deletions src/server.ts
Expand Up @@ -12,8 +12,7 @@ import { decodeMetadata, encodeMetadata, METADATA_HEADER_INTERNAL } from './meta
import { HTTPMethod } from './types.ts'
import { isNodeError, Logger } from './util.ts'

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

export enum Operation {
DELETE = 'delete',
Expand Down Expand Up @@ -367,10 +366,9 @@ export class BlobsServer {
return null
}

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

Expand Down

0 comments on commit 83875fd

Please sign in to comment.