1- import { Buffer } from 'node:buffer'
2- import { env } from 'node:process'
3-
1+ import { EnvironmentContext , getEnvironmentContext , MissingBlobsEnvironmentError } from './environment.ts'
42import { fetchAndRetry } from './retry.ts'
53import { BlobInput , Fetcher , HTTPMethod } from './types.ts'
64
7- /**
8- * The name of the environment variable that holds the context in a Base64,
9- * JSON-encoded object. If we ever need to change the encoding or the shape
10- * of this object, we should bump the version and create a new variable, so
11- * that the client knows how to consume the data and can advise the user to
12- * update the client if needed.
13- */
14- export const NETLIFY_CONTEXT_VARIABLE = 'NETLIFY_BLOBS_CONTEXT'
15-
16- export interface Context {
17- apiURL ?: string
18- edgeURL ?: string
19- siteID ?: string
20- token ?: string
21- }
22-
23- interface PopulatedContext extends Context {
24- siteID : string
25- token : string
26- }
27-
285interface MakeStoreRequestOptions {
296 body ?: BlobInput | null
307 headers ?: Record < string , string >
@@ -33,59 +10,45 @@ interface MakeStoreRequestOptions {
3310 storeName : string
3411}
3512
13+ export interface ClientOptions {
14+ apiURL ?: string
15+ edgeURL ?: string
16+ fetch ?: Fetcher
17+ siteID : string
18+ token : string
19+ }
20+
3621export class Client {
37- private context ?: Context
22+ private apiURL ?: string
23+ private edgeURL ?: string
3824 private fetch ?: Fetcher
25+ private siteID : string
26+ private token : string
3927
40- constructor ( context ?: Context , fetch ?: Fetcher ) {
41- this . context = context ?? { }
28+ constructor ( { apiURL, edgeURL, fetch, siteID, token } : ClientOptions ) {
29+ this . apiURL = apiURL
30+ this . edgeURL = edgeURL
4231 this . fetch = fetch
43- }
44-
45- private static getEnvironmentContext ( ) {
46- if ( ! env [ NETLIFY_CONTEXT_VARIABLE ] ) {
47- return
48- }
49-
50- const data = Buffer . from ( env [ NETLIFY_CONTEXT_VARIABLE ] , 'base64' ) . toString ( )
51-
52- try {
53- return JSON . parse ( data ) as Context
54- } catch {
55- // no-op
56- }
57- }
58-
59- private getContext ( ) {
60- const context = {
61- ...Client . getEnvironmentContext ( ) ,
62- ...this . context ,
63- }
64-
65- if ( ! context . siteID || ! context . token ) {
66- throw new Error ( `The blob store is unavailable because it's missing required configuration properties` )
67- }
68-
69- return context as PopulatedContext
32+ this . siteID = siteID
33+ this . token = token
7034 }
7135
7236 private async getFinalRequest ( storeName : string , key : string , method : string ) {
73- const context = this . getContext ( )
7437 const encodedKey = encodeURIComponent ( key )
7538
76- if ( ' edgeURL' in context ) {
39+ if ( this . edgeURL ) {
7740 return {
7841 headers : {
79- authorization : `Bearer ${ context . token } ` ,
42+ authorization : `Bearer ${ this . token } ` ,
8043 } ,
81- url : `${ context . edgeURL } /${ context . siteID } /${ storeName } /${ encodedKey } ` ,
44+ url : `${ this . edgeURL } /${ this . siteID } /${ storeName } /${ encodedKey } ` ,
8245 }
8346 }
8447
85- const apiURL = `${ context . apiURL ?? 'https://api.netlify.com' } /api/v1/sites/${
86- context . siteID
48+ const apiURL = `${ this . apiURL ?? 'https://api.netlify.com' } /api/v1/sites/${
49+ this . siteID
8750 } /blobs/${ encodedKey } ?context=${ storeName } `
88- const headers = { authorization : `Bearer ${ context . token } ` }
51+ const headers = { authorization : `Bearer ${ this . token } ` }
8952 const fetch = this . fetch ?? globalThis . fetch
9053 const res = await fetch ( apiURL , { headers, method } )
9154
@@ -137,3 +100,33 @@ export class Client {
137100 return res
138101 }
139102}
103+
104+ /**
105+ * Merges a set of options supplied by the user when getting a reference to a
106+ * store with a context object found in the environment.
107+ *
108+ * @param options User-supplied options
109+ * @param contextOverride Context to be used instead of the environment object
110+ */
111+ export const getClientOptions = (
112+ options : Partial < ClientOptions > ,
113+ contextOverride ?: EnvironmentContext ,
114+ ) : ClientOptions => {
115+ const context = contextOverride ?? getEnvironmentContext ( )
116+ const siteID = context . siteID ?? options . siteID
117+ const token = context . token ?? options . token
118+
119+ if ( ! siteID || ! token ) {
120+ throw new MissingBlobsEnvironmentError ( [ 'siteID' , 'token' ] )
121+ }
122+
123+ const clientOptions = {
124+ apiURL : context . apiURL ?? options . apiURL ,
125+ edgeURL : context . edgeURL ?? options . edgeURL ,
126+ fetch : options . fetch ,
127+ siteID,
128+ token,
129+ }
130+
131+ return clientOptions
132+ }
0 commit comments