1+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
12import { AwsClient } from "aws4fetch" ;
23import path from "path" ;
34import { RecoverableError } from "utils/error" ;
@@ -11,18 +12,46 @@ import {
1112} from "./constants" ;
1213import { TagCache } from "./types" ;
1314
14- const { CACHE_BUCKET_REGION , CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
15+ let awsClient : AwsClient | null = null ;
1516
16- const awsClient = new AwsClient ( {
17- accessKeyId : process . env . AWS_ACCESS_KEY_ID ! ,
18- secretAccessKey : process . env . AWS_SECRET_ACCESS_KEY ! ,
19- sessionToken : process . env . AWS_SESSION_TOKEN ,
20- region : CACHE_BUCKET_REGION ,
21- retries : parseNumberFromEnv ( process . env . AWS_SDK_S3_MAX_ATTEMPTS ) ,
22- } ) ;
23- const awsFetch = customFetchClient ( awsClient ) ;
17+ const getAwsClient = ( ) => {
18+ const { CACHE_BUCKET_REGION } = process . env ;
19+ if ( awsClient ) {
20+ return awsClient ;
21+ } else {
22+ awsClient = new AwsClient ( {
23+ accessKeyId : process . env . AWS_ACCESS_KEY_ID ! ,
24+ secretAccessKey : process . env . AWS_SECRET_ACCESS_KEY ! ,
25+ sessionToken : process . env . AWS_SESSION_TOKEN ,
26+ region : CACHE_BUCKET_REGION ,
27+ retries : parseNumberFromEnv ( process . env . AWS_SDK_S3_MAX_ATTEMPTS ) ,
28+ } ) ;
29+ return awsClient ;
30+ }
31+ } ;
32+ const awsFetch = (
33+ body : RequestInit [ "body" ] ,
34+ type : "query" | "batchWrite" = "query" ,
35+ ) => {
36+ const { CACHE_BUCKET_REGION } = process . env ;
37+ const client = getAwsClient ( ) ;
38+ return customFetchClient ( client ) (
39+ `https://dynamodb.${ CACHE_BUCKET_REGION } .amazonaws.com` ,
40+ {
41+ method : "POST" ,
42+ headers : {
43+ "Content-Type" : "application/x-amz-json-1.0" ,
44+ "X-Amz-Target" : `DynamoDB_20120810.${
45+ type === "query" ? "Query" : "BatchWriteItem"
46+ } `,
47+ } ,
48+ body,
49+ } ,
50+ ) ;
51+ } ;
2452
2553function buildDynamoKey ( key : string ) {
54+ const { NEXT_BUILD_ID } = process . env ;
2655 // FIXME: We should probably use something else than path.join here
2756 // this could transform some fetch cache key into a valid path
2857 return path . posix . join ( NEXT_BUILD_ID ?? "" , key ) ;
@@ -40,26 +69,19 @@ const tagCache: TagCache = {
4069 async getByPath ( path ) {
4170 try {
4271 if ( globalThis . disableDynamoDBCache ) return [ ] ;
72+ const { CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
4373 const result = await awsFetch (
44- `https://dynamodb. ${ CACHE_BUCKET_REGION } .amazonaws.com` ,
45- {
46- method : "POST " ,
47- headers : {
48- "Content-Type" : "application/x-amz-json-1.0" ,
49- "X-Amz-Target " : "DynamoDB_20120810.Query " ,
74+ JSON . stringify ( {
75+ TableName : CACHE_DYNAMO_TABLE ,
76+ IndexName : "revalidate " ,
77+ KeyConditionExpression : "#key = :key" ,
78+ ExpressionAttributeNames : {
79+ "#key " : "path " ,
5080 } ,
51- body : JSON . stringify ( {
52- TableName : CACHE_DYNAMO_TABLE ,
53- IndexName : "revalidate" ,
54- KeyConditionExpression : "#key = :key" ,
55- ExpressionAttributeNames : {
56- "#key" : "path" ,
57- } ,
58- ExpressionAttributeValues : {
59- ":key" : { S : buildDynamoKey ( path ) } ,
60- } ,
61- } ) ,
62- } ,
81+ ExpressionAttributeValues : {
82+ ":key" : { S : buildDynamoKey ( path ) } ,
83+ } ,
84+ } ) ,
6385 ) ;
6486 if ( result . status !== 200 ) {
6587 throw new RecoverableError (
@@ -80,25 +102,18 @@ const tagCache: TagCache = {
80102 async getByTag ( tag ) {
81103 try {
82104 if ( globalThis . disableDynamoDBCache ) return [ ] ;
105+ const { CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
83106 const result = await awsFetch (
84- `https://dynamodb.${ CACHE_BUCKET_REGION } .amazonaws.com` ,
85- {
86- method : "POST" ,
87- headers : {
88- "Content-Type" : "application/x-amz-json-1.0" ,
89- "X-Amz-Target" : "DynamoDB_20120810.Query" ,
107+ JSON . stringify ( {
108+ TableName : CACHE_DYNAMO_TABLE ,
109+ KeyConditionExpression : "#tag = :tag" ,
110+ ExpressionAttributeNames : {
111+ "#tag" : "tag" ,
90112 } ,
91- body : JSON . stringify ( {
92- TableName : CACHE_DYNAMO_TABLE ,
93- KeyConditionExpression : "#tag = :tag" ,
94- ExpressionAttributeNames : {
95- "#tag" : "tag" ,
96- } ,
97- ExpressionAttributeValues : {
98- ":tag" : { S : buildDynamoKey ( tag ) } ,
99- } ,
100- } ) ,
101- } ,
113+ ExpressionAttributeValues : {
114+ ":tag" : { S : buildDynamoKey ( tag ) } ,
115+ } ,
116+ } ) ,
102117 ) ;
103118 if ( result . status !== 200 ) {
104119 throw new RecoverableError ( `Failed to get by tag: ${ result . status } ` ) ;
@@ -119,29 +134,22 @@ const tagCache: TagCache = {
119134 async getLastModified ( key , lastModified ) {
120135 try {
121136 if ( globalThis . disableDynamoDBCache ) return lastModified ?? Date . now ( ) ;
137+ const { CACHE_DYNAMO_TABLE } = process . env ;
122138 const result = await awsFetch (
123- `https://dynamodb.${ CACHE_BUCKET_REGION } .amazonaws.com` ,
124- {
125- method : "POST" ,
126- headers : {
127- "Content-Type" : "application/x-amz-json-1.0" ,
128- "X-Amz-Target" : "DynamoDB_20120810.Query" ,
139+ JSON . stringify ( {
140+ TableName : CACHE_DYNAMO_TABLE ,
141+ IndexName : "revalidate" ,
142+ KeyConditionExpression :
143+ "#key = :key AND #revalidatedAt > :lastModified" ,
144+ ExpressionAttributeNames : {
145+ "#key" : "path" ,
146+ "#revalidatedAt" : "revalidatedAt" ,
129147 } ,
130- body : JSON . stringify ( {
131- TableName : CACHE_DYNAMO_TABLE ,
132- IndexName : "revalidate" ,
133- KeyConditionExpression :
134- "#key = :key AND #revalidatedAt > :lastModified" ,
135- ExpressionAttributeNames : {
136- "#key" : "path" ,
137- "#revalidatedAt" : "revalidatedAt" ,
138- } ,
139- ExpressionAttributeValues : {
140- ":key" : { S : buildDynamoKey ( key ) } ,
141- ":lastModified" : { N : String ( lastModified ?? 0 ) } ,
142- } ,
143- } ) ,
144- } ,
148+ ExpressionAttributeValues : {
149+ ":key" : { S : buildDynamoKey ( key ) } ,
150+ ":lastModified" : { N : String ( lastModified ?? 0 ) } ,
151+ } ,
152+ } ) ,
145153 ) ;
146154 if ( result . status !== 200 ) {
147155 throw new RecoverableError (
@@ -159,6 +167,7 @@ const tagCache: TagCache = {
159167 } ,
160168 async writeTags ( tags ) {
161169 try {
170+ const { CACHE_DYNAMO_TABLE } = process . env ;
162171 if ( globalThis . disableDynamoDBCache ) return ;
163172 const dataChunks = chunk ( tags , MAX_DYNAMO_BATCH_WRITE_ITEM_COUNT ) . map (
164173 ( Items ) => ( {
@@ -181,15 +190,8 @@ const tagCache: TagCache = {
181190 await Promise . all (
182191 paramsChunk . map ( async ( params ) => {
183192 const response = await awsFetch (
184- `https://dynamodb.${ CACHE_BUCKET_REGION } .amazonaws.com` ,
185- {
186- method : "POST" ,
187- headers : {
188- "Content-Type" : "application/x-amz-json-1.0" ,
189- "X-Amz-Target" : "DynamoDB_20120810.BatchWriteItem" ,
190- } ,
191- body : JSON . stringify ( params ) ,
192- } ,
193+ JSON . stringify ( params ) ,
194+ "batchWrite" ,
193195 ) ;
194196 if ( response . status !== 200 ) {
195197 throw new RecoverableError (
0 commit comments