1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
1
2
import { AwsClient } from "aws4fetch" ;
2
3
import path from "path" ;
3
4
import { RecoverableError } from "utils/error" ;
@@ -11,18 +12,46 @@ import {
11
12
} from "./constants" ;
12
13
import { TagCache } from "./types" ;
13
14
14
- const { CACHE_BUCKET_REGION , CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
15
+ let awsClient : AwsClient | null = null ;
15
16
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
+ } ;
24
52
25
53
function buildDynamoKey ( key : string ) {
54
+ const { NEXT_BUILD_ID } = process . env ;
26
55
// FIXME: We should probably use something else than path.join here
27
56
// this could transform some fetch cache key into a valid path
28
57
return path . posix . join ( NEXT_BUILD_ID ?? "" , key ) ;
@@ -40,26 +69,19 @@ const tagCache: TagCache = {
40
69
async getByPath ( path ) {
41
70
try {
42
71
if ( globalThis . disableDynamoDBCache ) return [ ] ;
72
+ const { CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
43
73
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 " ,
50
80
} ,
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
+ } ) ,
63
85
) ;
64
86
if ( result . status !== 200 ) {
65
87
throw new RecoverableError (
@@ -80,25 +102,18 @@ const tagCache: TagCache = {
80
102
async getByTag ( tag ) {
81
103
try {
82
104
if ( globalThis . disableDynamoDBCache ) return [ ] ;
105
+ const { CACHE_DYNAMO_TABLE , NEXT_BUILD_ID } = process . env ;
83
106
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" ,
90
112
} ,
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
+ } ) ,
102
117
) ;
103
118
if ( result . status !== 200 ) {
104
119
throw new RecoverableError ( `Failed to get by tag: ${ result . status } ` ) ;
@@ -119,29 +134,22 @@ const tagCache: TagCache = {
119
134
async getLastModified ( key , lastModified ) {
120
135
try {
121
136
if ( globalThis . disableDynamoDBCache ) return lastModified ?? Date . now ( ) ;
137
+ const { CACHE_DYNAMO_TABLE } = process . env ;
122
138
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" ,
129
147
} ,
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
+ } ) ,
145
153
) ;
146
154
if ( result . status !== 200 ) {
147
155
throw new RecoverableError (
@@ -159,6 +167,7 @@ const tagCache: TagCache = {
159
167
} ,
160
168
async writeTags ( tags ) {
161
169
try {
170
+ const { CACHE_DYNAMO_TABLE } = process . env ;
162
171
if ( globalThis . disableDynamoDBCache ) return ;
163
172
const dataChunks = chunk ( tags , MAX_DYNAMO_BATCH_WRITE_ITEM_COUNT ) . map (
164
173
( Items ) => ( {
@@ -181,15 +190,8 @@ const tagCache: TagCache = {
181
190
await Promise . all (
182
191
paramsChunk . map ( async ( params ) => {
183
192
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" ,
193
195
) ;
194
196
if ( response . status !== 200 ) {
195
197
throw new RecoverableError (
0 commit comments