Skip to content

Commit

Permalink
feat!: add listStores method (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Mar 4, 2024
1 parent 5ad27eb commit 3d0a386
Show file tree
Hide file tree
Showing 11 changed files with 472 additions and 113 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Expand Up @@ -23,6 +23,7 @@ module.exports = {
'unicorn/prefer-ternary': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }],
'func-style': 'off',
},
overrides: [
...overrides,
Expand Down
4 changes: 4 additions & 0 deletions src/backend/list_stores.ts
@@ -0,0 +1,4 @@
export interface ListStoresResponse {
stores: string[]
next_cursor?: string
}
28 changes: 18 additions & 10 deletions src/client.ts
Expand Up @@ -12,7 +12,7 @@ interface MakeStoreRequestOptions {
metadata?: Metadata
method: HTTPMethod
parameters?: Record<string, string>
storeName: string
storeName?: string
}

export interface ClientOptions {
Expand All @@ -31,7 +31,7 @@ interface GetFinalRequestOptions {
metadata?: Metadata
method: string
parameters?: Record<string, string>
storeName: string
storeName?: string
}

export class Client {
Expand Down Expand Up @@ -70,6 +70,16 @@ export class Client {
const encodedMetadata = encodeMetadata(metadata)
const consistency = opConsistency ?? this.consistency

let urlPath = `/${this.siteID}`

if (storeName) {
urlPath += `/${storeName}`
}

if (key) {
urlPath += `/${key}`
}

if (this.edgeURL) {
if (consistency === 'strong' && !this.uncachedEdgeURL) {
throw new BlobsConsistencyError()
Expand All @@ -83,8 +93,7 @@ export class Client {
headers[METADATA_HEADER_INTERNAL] = encodedMetadata
}

const path = key ? `/${this.siteID}/${storeName}/${key}` : `/${this.siteID}/${storeName}`
const url = new URL(path, consistency === 'strong' ? this.uncachedEdgeURL : this.edgeURL)
const url = new URL(urlPath, consistency === 'strong' ? this.uncachedEdgeURL : this.edgeURL)

for (const key in parameters) {
url.searchParams.set(key, parameters[key])
Expand All @@ -97,23 +106,22 @@ export class Client {
}

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

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

// If there is no key, we're dealing with the list endpoint, which is
// implemented directly in the Netlify API.
if (key === undefined) {
// If there is no store name, we're listing stores. If there's no key,
// we're listing blobs. Both operations are implemented directly in the
// Netlify API.
if (storeName === undefined || key === undefined) {
return {
headers: apiHeaders,
url: url.toString(),
}
}

url.pathname += `/${key}`

if (encodedMetadata) {
apiHeaders[METADATA_HEADER_EXTERNAL] = encodedMetadata
}
Expand Down
18 changes: 9 additions & 9 deletions src/consistency.test.ts
Expand Up @@ -52,17 +52,17 @@ describe('Consistency configuration', () => {
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})
.head({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(null, { headers }),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value, { headers }),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -107,17 +107,17 @@ describe('Consistency configuration', () => {
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})
.head({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(null, { headers }),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value, { headers }),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -213,17 +213,17 @@ describe('Consistency configuration', () => {
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value),
url: `${uncachedEdgeURL}/${siteID}/production/${key}`,
url: `${uncachedEdgeURL}/${siteID}/site:production/${key}`,
})
.head({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(null, { headers }),
url: `${edgeURL}/${siteID}/production/${key}`,
url: `${edgeURL}/${siteID}/site:production/${key}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value, { headers }),
url: `${edgeURL}/${siteID}/production/${key}`,
url: `${edgeURL}/${siteID}/site:production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down
4 changes: 2 additions & 2 deletions src/lambda_compat.test.ts
Expand Up @@ -48,12 +48,12 @@ describe('With edge credentials', () => {
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value),
url: `${edgeURL}/${siteID}/production/${key}`,
url: `${edgeURL}/${siteID}/site:production/${key}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
response: new Response(value),
url: `${edgeURL}/${siteID}/production/${key}`,
url: `${edgeURL}/${siteID}/site:production/${key}`,
})

globalThis.fetch = mockStore.fetch
Expand Down
44 changes: 22 additions & 22 deletions src/list.test.ts
Expand Up @@ -59,7 +59,7 @@ describe('list', () => {
next_cursor: 'cursor_1',
}),
),
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?cursor=cursor_1`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?cursor=cursor_2`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?directories=true`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_1`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?directories=true&cursor=cursor_2`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?prefix=dir2%2F&directories=true`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}?prefix=group%2F`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${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/blobs/${siteID}/${storeName}`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}`,
})
.get({
headers: { authorization: `Bearer ${apiToken}` },
Expand All @@ -319,7 +319,7 @@ describe('list', () => {
],
}),
),
url: `https://api.netlify.com/api/v1/blobs/${siteID}/${storeName}?cursor=cursor_2`,
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:${storeName}?cursor=cursor_2`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -373,7 +373,7 @@ describe('list', () => {
next_cursor: 'cursor_1',
}),
),
url: `${edgeURL}/${siteID}/${storeName}`,
url: `${edgeURL}/${siteID}/site:${storeName}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -397,7 +397,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `${edgeURL}/${siteID}/${storeName}?cursor=cursor_1`,
url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_1`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -414,7 +414,7 @@ describe('list', () => {
directories: [],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?cursor=cursor_2`,
url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_2`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -431,7 +431,7 @@ describe('list', () => {
directories: [],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?prefix=dir2%2F`,
url: `${edgeURL}/${siteID}/site:${storeName}?prefix=dir2%2F`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -487,7 +487,7 @@ describe('list', () => {
next_cursor: 'cursor_1',
}),
),
url: `${edgeURL}/${siteID}/${storeName}?directories=true`,
url: `${edgeURL}/${siteID}/site:${storeName}?directories=true`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -511,7 +511,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `${edgeURL}/${siteID}/${storeName}?directories=true&cursor=cursor_1`,
url: `${edgeURL}/${siteID}/site:${storeName}?directories=true&cursor=cursor_1`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -528,7 +528,7 @@ describe('list', () => {
directories: ['dir3'],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?directories=true&cursor=cursor_2`,
url: `${edgeURL}/${siteID}/site:${storeName}?directories=true&cursor=cursor_2`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -545,7 +545,7 @@ describe('list', () => {
directories: [],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?prefix=dir2%2F&directories=true`,
url: `${edgeURL}/${siteID}/site:${storeName}?prefix=dir2%2F&directories=true`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -598,7 +598,7 @@ describe('list', () => {
],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?prefix=group%2F`,
url: `${edgeURL}/${siteID}/site:${storeName}?prefix=group%2F`,
})

globalThis.fetch = mockStore.fetch
Expand Down Expand Up @@ -644,7 +644,7 @@ describe('list', () => {
next_cursor: 'cursor_2',
}),
),
url: `${edgeURL}/${siteID}/${storeName}`,
url: `${edgeURL}/${siteID}/site:${storeName}`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -667,7 +667,7 @@ describe('list', () => {
next_cursor: 'cursor_3',
}),
),
url: `${edgeURL}/${siteID}/${storeName}?cursor=cursor_2`,
url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_2`,
})
.get({
headers: { authorization: `Bearer ${edgeToken}` },
Expand All @@ -683,7 +683,7 @@ describe('list', () => {
],
}),
),
url: `${edgeURL}/${siteID}/${storeName}?cursor=cursor_3`,
url: `${edgeURL}/${siteID}/site:${storeName}?cursor=cursor_3`,
})

globalThis.fetch = mockStore.fetch
Expand Down

0 comments on commit 3d0a386

Please sign in to comment.