@reykjavik/webtools 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  - ... <!-- Add new lines here. -->
6
6
 
7
+ ## 0.1.9
8
+
9
+ _2023-04-27_
10
+
11
+ - `@reykjavik/webtools/http`
12
+ - feat: Add `toSec` TTL helper
13
+
7
14
  ## 0.1.7 – 0.1.8
8
15
 
9
16
  _2023-04-19_
package/README.md CHANGED
@@ -19,6 +19,7 @@ yarn add @reykjavik/webtools
19
19
  - [Types for HTTP Status code groups](#types-for-http-status-code-groups)
20
20
  - [`cacheControl` helper](#cachecontrol-helper)
21
21
  - [Type `TTLConfig`](#type-ttlconfig)
22
+ - [`toSec` TTL helper](#tosec-ttl-helper)
22
23
  - [`@reykjavik/webtools/next/http`](#reykjavikwebtoolsnexthttp)
23
24
  - [`makeErrorizeAppHOC`](#makeerrorizeapphoc)
24
25
  - [`showErrorPage` helper](#showerrorpage-helper)
@@ -155,6 +156,22 @@ Allows setting a "must-revalidate" flag instead of the default "immutable". A
155
156
  value of `"normal"` omits the flagging and falls back to HTTP's default
156
157
  behavior.
157
158
 
159
+ ### `toSec` TTL helper
160
+
161
+ **Syntax:** <code>toSec; (ttl: number | `${number}${'s'|'m'|'h'|'d'|'w'}`) =>
162
+ number</code>
163
+
164
+ Converts a `TTL` (max-age) value into seconds, and returns `0` for bad and/or
165
+ negative input values.
166
+
167
+ ```js
168
+ import type { toSec, TTL } from '@reykjavik/webtools/http';
169
+
170
+ const ttl: TTL = '2h';
171
+
172
+ const ttlSec = toSec(ttl);
173
+ ```
174
+
158
175
  ---
159
176
 
160
177
  ## `@reykjavik/webtools/next/http`
package/esm/http.d.ts CHANGED
@@ -115,7 +115,7 @@ export type HTTP_CLIENT_ERROR_ALL = HTTP_CLIENT_ERROR | typeof HTTP_405_MethodNo
115
115
  export type HTTP_SERVER_ERROR_ALL = HTTP_SERVER_ERROR | typeof HTTP_501_NotImplemented | typeof HTTP_502_BadGateway | typeof HTTP_503_ServiceUnavailable | typeof HTTP_504_GatewayTimeout | typeof HTTP_505_HTTPVersionNotSupported | typeof HTTP_506_VariantAlsoNegotiates | typeof HTTP_510_NotExtended | typeof HTTP_511_NetworkAuthenticationRequired;
116
116
  export type HTTP_ERROR_ALL = HTTP_CLIENT_ERROR_ALL | HTTP_SERVER_ERROR_ALL;
117
117
  type TimeUnit = 's' | 'm' | 'h' | 'd' | 'w';
118
- type TTL = number | `${number}${TimeUnit}`;
118
+ export type TTL = number | `${number}${TimeUnit}`;
119
119
  type TTLKeywords = 'permanent' | 'unset' | 'no-cache';
120
120
  type TTLObj = {
121
121
  /** Sets the cache `max-age=` for the resource. */
@@ -134,6 +134,13 @@ type TTLObj = {
134
134
  * @see https://github.com/reykjavikcity/webtools/tree/v0.1#type-ttlconfig
135
135
  */
136
136
  export type TTLConfig = TTL | TTLKeywords | TTLObj;
137
+ /**
138
+ * Converts a `TTL` (max-age) value into seconds, and returns `0` for bad
139
+ * and/or negative input values.
140
+ *
141
+ * @see https://github.com/reykjavikcity/webtools/tree/v0.1#tosec-ttl-helper
142
+ */
143
+ export declare const toSec: (ttl: TTL) => number;
137
144
  /**
138
145
  * Use this function to quickly set the `Cache-Control` header with a `max-age=`
139
146
  * on a HTTP response
package/esm/http.js CHANGED
@@ -110,16 +110,19 @@ const unitToSeconds = {
110
110
  d: 24 * 3600,
111
111
  w: 7 * 24 * 3600,
112
112
  };
113
- const toSec = (ttl) => {
114
- if (ttl == null) {
115
- return;
116
- }
113
+ /**
114
+ * Converts a `TTL` (max-age) value into seconds, and returns `0` for bad
115
+ * and/or negative input values.
116
+ *
117
+ * @see https://github.com/reykjavikcity/webtools/tree/v0.1#tosec-ttl-helper
118
+ */
119
+ export const toSec = (ttl) => {
117
120
  if (typeof ttl === 'string') {
118
121
  const value = parseFloat(ttl);
119
122
  const factor = unitToSeconds[ttl.slice(-1)] || 1;
120
123
  ttl = value * factor;
121
124
  }
122
- return !isNaN(ttl) ? ttl : undefined;
125
+ return Math.max(0, Math.round(ttl)) || 0;
123
126
  };
124
127
  const stabilities = {
125
128
  revalidate: ', must-revalidate',
@@ -163,22 +166,21 @@ export const cacheControl = (response, ttlCfg, eTag) => {
163
166
  maxAge = undefined;
164
167
  }
165
168
  }
166
- maxAge = toSec(maxAge);
167
169
  if (maxAge == null) {
168
170
  response.removeHeader('Cache-Control');
169
171
  return;
170
172
  }
171
- const sWR_ttl = toSec(opts.staleWhileRevalidate);
172
- const sWR = sWR_ttl != null ? `, stale-while-revalidate=${sWR_ttl}` : '';
173
- const sIE_ttl = toSec(opts.staleIfError);
174
- const sIE = sIE_ttl != null ? `, stale-if-error=${sIE_ttl}` : '';
175
- maxAge = Math.round(maxAge);
176
- if (maxAge <= 0) {
173
+ maxAge = toSec(maxAge);
174
+ if (!maxAge) {
177
175
  setCC(response, 'no-cache');
178
176
  return;
179
177
  }
178
+ const sWR_ttl = toSec(opts.staleWhileRevalidate || 0);
179
+ const sWR = sWR_ttl ? `, stale-while-revalidate=${sWR_ttl}` : '';
180
+ const sIE_ttl = toSec(opts.staleIfError || 0);
181
+ const sIE = sIE_ttl ? `, stale-if-error=${sIE_ttl}` : '';
180
182
  const scope = opts.publ ? 'public' : 'private';
181
183
  const stability = (opts.stability && stabilities[opts.stability]) || stabilities.immutable;
182
- eTag != null && response.setHeader('ETag', eTag);
183
184
  setCC(response, `${scope}, max-age=${maxAge + sWR + sIE + stability}`);
185
+ eTag != null && response.setHeader('ETag', eTag);
184
186
  };
package/http.d.ts CHANGED
@@ -115,7 +115,7 @@ export type HTTP_CLIENT_ERROR_ALL = HTTP_CLIENT_ERROR | typeof HTTP_405_MethodNo
115
115
  export type HTTP_SERVER_ERROR_ALL = HTTP_SERVER_ERROR | typeof HTTP_501_NotImplemented | typeof HTTP_502_BadGateway | typeof HTTP_503_ServiceUnavailable | typeof HTTP_504_GatewayTimeout | typeof HTTP_505_HTTPVersionNotSupported | typeof HTTP_506_VariantAlsoNegotiates | typeof HTTP_510_NotExtended | typeof HTTP_511_NetworkAuthenticationRequired;
116
116
  export type HTTP_ERROR_ALL = HTTP_CLIENT_ERROR_ALL | HTTP_SERVER_ERROR_ALL;
117
117
  type TimeUnit = 's' | 'm' | 'h' | 'd' | 'w';
118
- type TTL = number | `${number}${TimeUnit}`;
118
+ export type TTL = number | `${number}${TimeUnit}`;
119
119
  type TTLKeywords = 'permanent' | 'unset' | 'no-cache';
120
120
  type TTLObj = {
121
121
  /** Sets the cache `max-age=` for the resource. */
@@ -134,6 +134,13 @@ type TTLObj = {
134
134
  * @see https://github.com/reykjavikcity/webtools/tree/v0.1#type-ttlconfig
135
135
  */
136
136
  export type TTLConfig = TTL | TTLKeywords | TTLObj;
137
+ /**
138
+ * Converts a `TTL` (max-age) value into seconds, and returns `0` for bad
139
+ * and/or negative input values.
140
+ *
141
+ * @see https://github.com/reykjavikcity/webtools/tree/v0.1#tosec-ttl-helper
142
+ */
143
+ export declare const toSec: (ttl: TTL) => number;
137
144
  /**
138
145
  * Use this function to quickly set the `Cache-Control` header with a `max-age=`
139
146
  * on a HTTP response
package/http.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cacheControl = exports.HTTP_511_NetworkAuthenticationRequired = exports.HTTP_510_NotExtended = exports.HTTP_506_VariantAlsoNegotiates = exports.HTTP_505_HTTPVersionNotSupported = exports.HTTP_504_GatewayTimeout = exports.HTTP_503_ServiceUnavailable = exports.HTTP_502_BadGateway = exports.HTTP_501_NotImplemented = exports.HTTP_500_InternalServerError = exports.HTTP_451_UnavailableForLegalReasons = exports.HTTP_431_RequestHeaderFieldsTooLarge = exports.HTTP_429_TooManyRequests = exports.HTTP_428_PreconditionRequired = exports.HTTP_426_UpgradeRequired = exports.HTTP_421_MisdirectedRequest = exports.HTTP_418_ImATeapot = exports.HTTP_417_ExpectationFailed = exports.HTTP_416_RangeNotSatisfiable = exports.HTTP_415_UnsupportedMediaType = exports.HTTP_414_URITooLong = exports.HTTP_413_PayloadTooLarge = exports.HTTP_412_PreconditionFailed = exports.HTTP_411_LengthRequired = exports.HTTP_410_Gone = exports.HTTP_409_Conflict = exports.HTTP_408_RequestTimeout = exports.HTTP_407_ProxyAuthenticationRequired = exports.HTTP_406_NotAcceptable = exports.HTTP_405_MethodNotAllowed = exports.HTTP_404_NotFound = exports.HTTP_403_Forbidden = exports.HTTP_401_Unauthorized = exports.HTTP_400_BadRequest = exports.HTTP_308_PermanentRedirect = exports.HTTP_307_TemporaryRedirect = exports.HTTP_304_NotModified = exports.HTTP_303_SeeOther = exports.HTTP_302_Found = exports.HTTP_301_MovedPermanently = exports.HTTP_206_PartialContent = exports.HTTP_204_NoContent = exports.HTTP_203_NonAuthoritativeInformation = exports.HTTP_202_Accepted = exports.HTTP_201_Created = exports.HTTP_200_OK = exports.HTTP_101_SwitchingProtocols = exports.HTTP_100_Continue = void 0;
3
+ exports.cacheControl = exports.toSec = exports.HTTP_511_NetworkAuthenticationRequired = exports.HTTP_510_NotExtended = exports.HTTP_506_VariantAlsoNegotiates = exports.HTTP_505_HTTPVersionNotSupported = exports.HTTP_504_GatewayTimeout = exports.HTTP_503_ServiceUnavailable = exports.HTTP_502_BadGateway = exports.HTTP_501_NotImplemented = exports.HTTP_500_InternalServerError = exports.HTTP_451_UnavailableForLegalReasons = exports.HTTP_431_RequestHeaderFieldsTooLarge = exports.HTTP_429_TooManyRequests = exports.HTTP_428_PreconditionRequired = exports.HTTP_426_UpgradeRequired = exports.HTTP_421_MisdirectedRequest = exports.HTTP_418_ImATeapot = exports.HTTP_417_ExpectationFailed = exports.HTTP_416_RangeNotSatisfiable = exports.HTTP_415_UnsupportedMediaType = exports.HTTP_414_URITooLong = exports.HTTP_413_PayloadTooLarge = exports.HTTP_412_PreconditionFailed = exports.HTTP_411_LengthRequired = exports.HTTP_410_Gone = exports.HTTP_409_Conflict = exports.HTTP_408_RequestTimeout = exports.HTTP_407_ProxyAuthenticationRequired = exports.HTTP_406_NotAcceptable = exports.HTTP_405_MethodNotAllowed = exports.HTTP_404_NotFound = exports.HTTP_403_Forbidden = exports.HTTP_401_Unauthorized = exports.HTTP_400_BadRequest = exports.HTTP_308_PermanentRedirect = exports.HTTP_307_TemporaryRedirect = exports.HTTP_304_NotModified = exports.HTTP_303_SeeOther = exports.HTTP_302_Found = exports.HTTP_301_MovedPermanently = exports.HTTP_206_PartialContent = exports.HTTP_204_NoContent = exports.HTTP_203_NonAuthoritativeInformation = exports.HTTP_202_Accepted = exports.HTTP_201_Created = exports.HTTP_200_OK = exports.HTTP_101_SwitchingProtocols = exports.HTTP_100_Continue = void 0;
4
4
  // INFORMATION
5
5
  /** The client should continue the request or ignore the response if the request is already finished. */
6
6
  exports.HTTP_100_Continue = 100;
@@ -113,17 +113,21 @@ const unitToSeconds = {
113
113
  d: 24 * 3600,
114
114
  w: 7 * 24 * 3600,
115
115
  };
116
+ /**
117
+ * Converts a `TTL` (max-age) value into seconds, and returns `0` for bad
118
+ * and/or negative input values.
119
+ *
120
+ * @see https://github.com/reykjavikcity/webtools/tree/v0.1#tosec-ttl-helper
121
+ */
116
122
  const toSec = (ttl) => {
117
- if (ttl == null) {
118
- return;
119
- }
120
123
  if (typeof ttl === 'string') {
121
124
  const value = parseFloat(ttl);
122
125
  const factor = unitToSeconds[ttl.slice(-1)] || 1;
123
126
  ttl = value * factor;
124
127
  }
125
- return !isNaN(ttl) ? ttl : undefined;
128
+ return Math.max(0, Math.round(ttl)) || 0;
126
129
  };
130
+ exports.toSec = toSec;
127
131
  const stabilities = {
128
132
  revalidate: ', must-revalidate',
129
133
  immutable: ', immutable',
@@ -166,23 +170,22 @@ const cacheControl = (response, ttlCfg, eTag) => {
166
170
  maxAge = undefined;
167
171
  }
168
172
  }
169
- maxAge = toSec(maxAge);
170
173
  if (maxAge == null) {
171
174
  response.removeHeader('Cache-Control');
172
175
  return;
173
176
  }
174
- const sWR_ttl = toSec(opts.staleWhileRevalidate);
175
- const sWR = sWR_ttl != null ? `, stale-while-revalidate=${sWR_ttl}` : '';
176
- const sIE_ttl = toSec(opts.staleIfError);
177
- const sIE = sIE_ttl != null ? `, stale-if-error=${sIE_ttl}` : '';
178
- maxAge = Math.round(maxAge);
179
- if (maxAge <= 0) {
177
+ maxAge = (0, exports.toSec)(maxAge);
178
+ if (!maxAge) {
180
179
  setCC(response, 'no-cache');
181
180
  return;
182
181
  }
182
+ const sWR_ttl = (0, exports.toSec)(opts.staleWhileRevalidate || 0);
183
+ const sWR = sWR_ttl ? `, stale-while-revalidate=${sWR_ttl}` : '';
184
+ const sIE_ttl = (0, exports.toSec)(opts.staleIfError || 0);
185
+ const sIE = sIE_ttl ? `, stale-if-error=${sIE_ttl}` : '';
183
186
  const scope = opts.publ ? 'public' : 'private';
184
187
  const stability = (opts.stability && stabilities[opts.stability]) || stabilities.immutable;
185
- eTag != null && response.setHeader('ETag', eTag);
186
188
  setCC(response, `${scope}, max-age=${maxAge + sWR + sIE + stability}`);
189
+ eTag != null && response.setHeader('ETag', eTag);
187
190
  };
188
191
  exports.cacheControl = cacheControl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/webtools",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Misc. JS/TS helpers used by Reykjavík City's web dev teams.",
5
5
  "main": "index.js",
6
6
  "repository": "ssh://git@github.com:reykjavikcity/webtools.git",