@@ -168,10 +168,63 @@ function resolveDurationExpiration(options = {}, { required = false } = {}) {
168168
169169 return {
170170 rawExpiresIn,
171+ expiresIn,
171172 exp : Date . now ( ) + expiresIn ,
172173 } ;
173174}
174175
176+ const DURATION_INPUT_UNIT_MS = {
177+ day : 24 * 60 * 60 * 1000 ,
178+ month : 30 * 24 * 60 * 60 * 1000 ,
179+ season : 90 * 24 * 60 * 60 * 1000 ,
180+ year : 365 * 24 * 60 * 60 * 1000 ,
181+ } ;
182+
183+ function resolveDurationInput ( options = { } , durationExpiration ) {
184+ const rawExpiresValue = options ?. expiresValue ;
185+ const rawExpiresUnit = options ?. expiresUnit ;
186+ const hasExpiresValue = rawExpiresValue != null && rawExpiresValue !== '' ;
187+ const hasExpiresUnit = rawExpiresUnit != null && rawExpiresUnit !== '' ;
188+ if ( ! hasExpiresValue && ! hasExpiresUnit ) {
189+ return null ;
190+ }
191+
192+ const expiresValue = Number ( rawExpiresValue ) ;
193+ if ( ! Number . isFinite ( expiresValue ) || expiresValue <= 0 ) {
194+ throw new RequestInvalidError (
195+ 'INVALID_EXPIRES_VALUE' ,
196+ `Invalid expiresValue option: ${ rawExpiresValue } ` ,
197+ ) ;
198+ }
199+
200+ const expiresUnit =
201+ typeof rawExpiresUnit === 'string' ? rawExpiresUnit . trim ( ) : '' ;
202+ if ( ! [ 'day' , 'month' , 'season' , 'year' ] . includes ( expiresUnit ) ) {
203+ throw new RequestInvalidError (
204+ 'INVALID_EXPIRES_UNIT' ,
205+ `Invalid expiresUnit option: ${ rawExpiresUnit } ` ,
206+ ) ;
207+ }
208+
209+ const normalizedExpiresValue = Number ( expiresValue . toFixed ( 2 ) ) ;
210+ const expectedExpiresIn =
211+ normalizedExpiresValue * DURATION_INPUT_UNIT_MS [ expiresUnit ] ;
212+ if (
213+ durationExpiration &&
214+ Math . abs ( durationExpiration . expiresIn - expectedExpiresIn ) > 1
215+ ) {
216+ throw new RequestInvalidError (
217+ 'INVALID_DURATION_INPUT' ,
218+ `expiresValue/expiresUnit do not match expiresIn option: ${ rawExpiresValue } ${ expiresUnit } != ${ options ?. expiresIn } ` ,
219+ ) ;
220+ }
221+
222+ return {
223+ expiresValue : String ( normalizedExpiresValue ) ,
224+ expiresUnit,
225+ } ;
226+ }
227+
175228function resolveCountExpiration ( options = { } ) {
176229 const rawCount = options ?. count ;
177230 if ( rawCount == null || rawCount === '' ) {
@@ -275,6 +328,7 @@ function createTokenItem(payload, options = {}) {
275328 normalizeExpirationMode ( options ?. mode ) ??
276329 inferLegacyExpirationMode ( options ) ;
277330 let durationExpiration = null ;
331+ let durationInput = null ;
278332 let exp ;
279333 let countExpiration = null ;
280334 if ( expirationMode === 'datetime' ) {
@@ -285,6 +339,9 @@ function createTokenItem(payload, options = {}) {
285339 durationExpiration = resolveDurationExpiration ( options , {
286340 required : expirationMode === 'duration' ,
287341 } ) ;
342+ if ( durationExpiration ) {
343+ durationInput = resolveDurationInput ( options , durationExpiration ) ;
344+ }
288345 exp = durationExpiration ?. exp ;
289346 }
290347
@@ -314,6 +371,8 @@ function createTokenItem(payload, options = {}) {
314371 delete safePayload . mode ;
315372 delete safePayload . exp ;
316373 delete safePayload . expiresIn ;
374+ delete safePayload . expiresValue ;
375+ delete safePayload . expiresUnit ;
317376 delete safePayload . count ;
318377 delete safePayload . usedCount ;
319378 normalizeAgePublicKeyConfig ( safePayload ) ;
@@ -332,6 +391,7 @@ function createTokenItem(payload, options = {}) {
332391 : durationExpiration
333392 ? {
334393 expiresIn : durationExpiration . rawExpiresIn ,
394+ ...( durationInput || { } ) ,
335395 exp,
336396 }
337397 : { } ) ,
0 commit comments