construct-hub 0.4.406 → 0.4.407

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.
@@ -393,7 +393,7 @@ class ConstructHub extends constructs_1.Construct {
393
393
  }
394
394
  exports.ConstructHub = ConstructHub;
395
395
  _a = JSII_RTTI_SYMBOL_1;
396
- ConstructHub[_a] = { fqn: "construct-hub.ConstructHub", version: "0.4.406" };
396
+ ConstructHub[_a] = { fqn: "construct-hub.ConstructHub", version: "0.4.407" };
397
397
  /**
398
398
  * How possibly risky operations (such as doc-generation, which requires
399
399
  * installing the indexed packages in order to trans-literate sample code) are
@@ -1645,6 +1645,17 @@ var require_http_cache_semantics = __commonJS({
1645
1645
  return parts.join(", ");
1646
1646
  }
1647
1647
  module2.exports = class CachePolicy {
1648
+ /**
1649
+ * Creates a new CachePolicy instance.
1650
+ * @param {HttpRequest} req - Incoming client request.
1651
+ * @param {HttpResponse} res - Received server response.
1652
+ * @param {Object} [options={}] - Configuration options.
1653
+ * @param {boolean} [options.shared=true] - Is the cache shared (a public proxy)? `false` for personal browser caches.
1654
+ * @param {number} [options.cacheHeuristic=0.1] - Fallback heuristic (age fraction) for cache duration.
1655
+ * @param {number} [options.immutableMinTimeToLive=86400000] - Minimum TTL for immutable responses in milliseconds.
1656
+ * @param {boolean} [options.ignoreCargoCult=false] - Detect nonsense cache headers, and override them.
1657
+ * @param {any} [options._fromObject] - Internal parameter for deserialization. Do not use.
1658
+ */
1648
1659
  constructor(req, res, {
1649
1660
  shared,
1650
1661
  cacheHeuristic,
@@ -1662,6 +1673,7 @@ var require_http_cache_semantics = __commonJS({
1662
1673
  this._assertRequestHasHeaders(req);
1663
1674
  this._responseTime = this.now();
1664
1675
  this._isShared = shared !== false;
1676
+ this._ignoreCargoCult = !!ignoreCargoCult;
1665
1677
  this._cacheHeuristic = void 0 !== cacheHeuristic ? cacheHeuristic : 0.1;
1666
1678
  this._immutableMinTtl = void 0 !== immutableMinTimeToLive ? immutableMinTimeToLive : 24 * 3600 * 1e3;
1667
1679
  this._status = "status" in res ? res.status : 200;
@@ -1673,7 +1685,7 @@ var require_http_cache_semantics = __commonJS({
1673
1685
  this._noAuthorization = !req.headers.authorization;
1674
1686
  this._reqHeaders = res.headers.vary ? req.headers : null;
1675
1687
  this._reqcc = parseCacheControl(req.headers["cache-control"]);
1676
- if (ignoreCargoCult && "pre-check" in this._rescc && "post-check" in this._rescc) {
1688
+ if (this._ignoreCargoCult && "pre-check" in this._rescc && "post-check" in this._rescc) {
1677
1689
  delete this._rescc["pre-check"];
1678
1690
  delete this._rescc["post-check"];
1679
1691
  delete this._rescc["no-cache"];
@@ -1689,9 +1701,17 @@ var require_http_cache_semantics = __commonJS({
1689
1701
  this._rescc["no-cache"] = true;
1690
1702
  }
1691
1703
  }
1704
+ /**
1705
+ * You can monkey-patch it for testing.
1706
+ * @returns {number} Current time in milliseconds.
1707
+ */
1692
1708
  now() {
1693
1709
  return Date.now();
1694
1710
  }
1711
+ /**
1712
+ * Determines if the response is storable in a cache.
1713
+ * @returns {boolean} `false` if can never be cached.
1714
+ */
1695
1715
  storable() {
1696
1716
  return !!(!this._reqcc["no-store"] && // A cache MUST NOT store a response to any request, unless:
1697
1717
  // The request method is understood by the cache and defined as being cacheable, and
@@ -1707,42 +1727,142 @@ var require_http_cache_semantics = __commonJS({
1707
1727
  this._rescc["max-age"] || this._isShared && this._rescc["s-maxage"] || this._rescc.public || // has a status code that is defined as cacheable by default
1708
1728
  statusCodeCacheableByDefault.has(this._status)));
1709
1729
  }
1730
+ /**
1731
+ * @returns {boolean} true if expiration is explicitly defined.
1732
+ */
1710
1733
  _hasExplicitExpiration() {
1711
- return this._isShared && this._rescc["s-maxage"] || this._rescc["max-age"] || this._resHeaders.expires;
1734
+ return !!(this._isShared && this._rescc["s-maxage"] || this._rescc["max-age"] || this._resHeaders.expires);
1712
1735
  }
1736
+ /**
1737
+ * @param {HttpRequest} req - a request
1738
+ * @throws {Error} if the headers are missing.
1739
+ */
1713
1740
  _assertRequestHasHeaders(req) {
1714
1741
  if (!req || !req.headers) {
1715
1742
  throw Error("Request headers missing");
1716
1743
  }
1717
1744
  }
1745
+ /**
1746
+ * Checks if the request matches the cache and can be satisfied from the cache immediately,
1747
+ * without having to make a request to the server.
1748
+ *
1749
+ * This doesn't support `stale-while-revalidate`. See `evaluateRequest()` for a more complete solution.
1750
+ *
1751
+ * @param {HttpRequest} req - The new incoming HTTP request.
1752
+ * @returns {boolean} `true`` if the cached response used to construct this cache policy satisfies the request without revalidation.
1753
+ */
1718
1754
  satisfiesWithoutRevalidation(req) {
1755
+ const result = this.evaluateRequest(req);
1756
+ return !result.revalidation;
1757
+ }
1758
+ /**
1759
+ * @param {{headers: Record<string, string>, synchronous: boolean}|undefined} revalidation - Revalidation information, if any.
1760
+ * @returns {{response: {headers: Record<string, string>}, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object with a cached response headers and revalidation info.
1761
+ */
1762
+ _evaluateRequestHitResult(revalidation) {
1763
+ return {
1764
+ response: {
1765
+ headers: this.responseHeaders()
1766
+ },
1767
+ revalidation
1768
+ };
1769
+ }
1770
+ /**
1771
+ * @param {HttpRequest} request - new incoming
1772
+ * @param {boolean} synchronous - whether revalidation must be synchronous (not s-w-r).
1773
+ * @returns {{headers: Record<string, string>, synchronous: boolean}} An object with revalidation headers and a synchronous flag.
1774
+ */
1775
+ _evaluateRequestRevalidation(request, synchronous) {
1776
+ return {
1777
+ synchronous,
1778
+ headers: this.revalidationHeaders(request)
1779
+ };
1780
+ }
1781
+ /**
1782
+ * @param {HttpRequest} request - new incoming
1783
+ * @returns {{response: undefined, revalidation: {headers: Record<string, string>, synchronous: boolean}}} An object indicating no cached response and revalidation details.
1784
+ */
1785
+ _evaluateRequestMissResult(request) {
1786
+ return {
1787
+ response: void 0,
1788
+ revalidation: this._evaluateRequestRevalidation(request, true)
1789
+ };
1790
+ }
1791
+ /**
1792
+ * Checks if the given request matches this cache entry, and how the cache can be used to satisfy it. Returns an object with:
1793
+ *
1794
+ * ```
1795
+ * {
1796
+ * // If defined, you must send a request to the server.
1797
+ * revalidation: {
1798
+ * headers: {}, // HTTP headers to use when sending the revalidation response
1799
+ * // If true, you MUST wait for a response from the server before using the cache
1800
+ * // If false, this is stale-while-revalidate. The cache is stale, but you can use it while you update it asynchronously.
1801
+ * synchronous: bool,
1802
+ * },
1803
+ * // If defined, you can use this cached response.
1804
+ * response: {
1805
+ * headers: {}, // Updated cached HTTP headers you must use when responding to the client
1806
+ * },
1807
+ * }
1808
+ * ```
1809
+ * @param {HttpRequest} req - new incoming HTTP request
1810
+ * @returns {{response: {headers: Record<string, string>}|undefined, revalidation: {headers: Record<string, string>, synchronous: boolean}|undefined}} An object containing keys:
1811
+ * - revalidation: { headers: Record<string, string>, synchronous: boolean } Set if you should send this to the origin server
1812
+ * - response: { headers: Record<string, string> } Set if you can respond to the client with these cached headers
1813
+ */
1814
+ evaluateRequest(req) {
1719
1815
  this._assertRequestHasHeaders(req);
1816
+ if (this._rescc["must-revalidate"]) {
1817
+ return this._evaluateRequestMissResult(req);
1818
+ }
1819
+ if (!this._requestMatches(req, false)) {
1820
+ return this._evaluateRequestMissResult(req);
1821
+ }
1720
1822
  const requestCC = parseCacheControl(req.headers["cache-control"]);
1721
1823
  if (requestCC["no-cache"] || /no-cache/.test(req.headers.pragma)) {
1722
- return false;
1824
+ return this._evaluateRequestMissResult(req);
1723
1825
  }
1724
- if (requestCC["max-age"] && this.age() > requestCC["max-age"]) {
1725
- return false;
1826
+ if (requestCC["max-age"] && this.age() > toNumberOrZero(requestCC["max-age"])) {
1827
+ return this._evaluateRequestMissResult(req);
1726
1828
  }
1727
- if (requestCC["min-fresh"] && this.timeToLive() < 1e3 * requestCC["min-fresh"]) {
1728
- return false;
1829
+ if (requestCC["min-fresh"] && this.maxAge() - this.age() < toNumberOrZero(requestCC["min-fresh"])) {
1830
+ return this._evaluateRequestMissResult(req);
1729
1831
  }
1730
1832
  if (this.stale()) {
1731
- const allowsStale = requestCC["max-stale"] && !this._rescc["must-revalidate"] && (true === requestCC["max-stale"] || requestCC["max-stale"] > this.age() - this.maxAge());
1732
- if (!allowsStale) {
1733
- return false;
1833
+ const allowsStaleWithoutRevalidation = "max-stale" in requestCC && (true === requestCC["max-stale"] || requestCC["max-stale"] > this.age() - this.maxAge());
1834
+ if (allowsStaleWithoutRevalidation) {
1835
+ return this._evaluateRequestHitResult(void 0);
1734
1836
  }
1837
+ if (this.useStaleWhileRevalidate()) {
1838
+ return this._evaluateRequestHitResult(this._evaluateRequestRevalidation(req, false));
1839
+ }
1840
+ return this._evaluateRequestMissResult(req);
1735
1841
  }
1736
- return this._requestMatches(req, false);
1842
+ return this._evaluateRequestHitResult(void 0);
1737
1843
  }
1844
+ /**
1845
+ * @param {HttpRequest} req - check if this is for the same cache entry
1846
+ * @param {boolean} allowHeadMethod - allow a HEAD method to match.
1847
+ * @returns {boolean} `true` if the request matches.
1848
+ */
1738
1849
  _requestMatches(req, allowHeadMethod) {
1739
- return (!this._url || this._url === req.url) && this._host === req.headers.host && // the request method associated with the stored response allows it to be used for the presented request, and
1850
+ return !!((!this._url || this._url === req.url) && this._host === req.headers.host && // the request method associated with the stored response allows it to be used for the presented request, and
1740
1851
  (!req.method || this._method === req.method || allowHeadMethod && "HEAD" === req.method) && // selecting header fields nominated by the stored response (if any) match those presented, and
1741
- this._varyMatches(req);
1852
+ this._varyMatches(req));
1742
1853
  }
1854
+ /**
1855
+ * Determines whether storing authenticated responses is allowed.
1856
+ * @returns {boolean} `true` if allowed.
1857
+ */
1743
1858
  _allowsStoringAuthenticated() {
1744
- return this._rescc["must-revalidate"] || this._rescc.public || this._rescc["s-maxage"];
1859
+ return !!(this._rescc["must-revalidate"] || this._rescc.public || this._rescc["s-maxage"]);
1745
1860
  }
1861
+ /**
1862
+ * Checks whether the Vary header in the response matches the new request.
1863
+ * @param {HttpRequest} req - incoming HTTP request
1864
+ * @returns {boolean} `true` if the vary headers match.
1865
+ */
1746
1866
  _varyMatches(req) {
1747
1867
  if (!this._resHeaders.vary) {
1748
1868
  return true;
@@ -1756,6 +1876,11 @@ var require_http_cache_semantics = __commonJS({
1756
1876
  }
1757
1877
  return true;
1758
1878
  }
1879
+ /**
1880
+ * Creates a copy of the given headers without any hop-by-hop headers.
1881
+ * @param {Record<string, string>} inHeaders - old headers from the cached response
1882
+ * @returns {Record<string, string>} A new headers object without hop-by-hop headers.
1883
+ */
1759
1884
  _copyWithoutHopByHopHeaders(inHeaders) {
1760
1885
  const headers = {};
1761
1886
  for (const name in inHeaders) {
@@ -1780,6 +1905,11 @@ var require_http_cache_semantics = __commonJS({
1780
1905
  }
1781
1906
  return headers;
1782
1907
  }
1908
+ /**
1909
+ * Returns the response headers adjusted for serving the cached response.
1910
+ * Removes hop-by-hop headers and updates the Age and Date headers.
1911
+ * @returns {Record<string, string>} The adjusted response headers.
1912
+ */
1783
1913
  responseHeaders() {
1784
1914
  const headers = this._copyWithoutHopByHopHeaders(this._resHeaders);
1785
1915
  const age = this.age();
@@ -1791,8 +1921,8 @@ var require_http_cache_semantics = __commonJS({
1791
1921
  return headers;
1792
1922
  }
1793
1923
  /**
1794
- * Value of the Date response header or current time if Date was invalid
1795
- * @return timestamp
1924
+ * Returns the Date header value from the response or the current time if invalid.
1925
+ * @returns {number} Timestamp (in milliseconds) representing the Date header or response time.
1796
1926
  */
1797
1927
  date() {
1798
1928
  const serverDate = Date.parse(this._resHeaders.date);
@@ -1804,23 +1934,27 @@ var require_http_cache_semantics = __commonJS({
1804
1934
  /**
1805
1935
  * Value of the Age header, in seconds, updated for the current time.
1806
1936
  * May be fractional.
1807
- *
1808
- * @return Number
1937
+ * @returns {number} The age in seconds.
1809
1938
  */
1810
1939
  age() {
1811
1940
  let age = this._ageValue();
1812
1941
  const residentTime = (this.now() - this._responseTime) / 1e3;
1813
1942
  return age + residentTime;
1814
1943
  }
1944
+ /**
1945
+ * @returns {number} The Age header value as a number.
1946
+ */
1815
1947
  _ageValue() {
1816
1948
  return toNumberOrZero(this._resHeaders.age);
1817
1949
  }
1818
1950
  /**
1819
- * Value of applicable max-age (or heuristic equivalent) in seconds. This counts since response's `Date`.
1951
+ * Possibly outdated value of applicable max-age (or heuristic equivalent) in seconds.
1952
+ * This counts since response's `Date`.
1820
1953
  *
1821
1954
  * For an up-to-date value, see `timeToLive()`.
1822
1955
  *
1823
- * @return Number
1956
+ * Returns the maximum age (freshness lifetime) of the response in seconds.
1957
+ * @returns {number} The max-age value in seconds.
1824
1958
  */
1825
1959
  maxAge() {
1826
1960
  if (!this.storable() || this._rescc["no-cache"]) {
@@ -1863,24 +1997,52 @@ var require_http_cache_semantics = __commonJS({
1863
1997
  }
1864
1998
  return defaultMinTtl;
1865
1999
  }
2000
+ /**
2001
+ * Remaining time this cache entry may be useful for, in *milliseconds*.
2002
+ * You can use this as an expiration time for your cache storage.
2003
+ *
2004
+ * Prefer this method over `maxAge()`, because it includes other factors like `age` and `stale-while-revalidate`.
2005
+ * @returns {number} Time-to-live in milliseconds.
2006
+ */
1866
2007
  timeToLive() {
1867
2008
  const age = this.maxAge() - this.age();
1868
2009
  const staleIfErrorAge = age + toNumberOrZero(this._rescc["stale-if-error"]);
1869
2010
  const staleWhileRevalidateAge = age + toNumberOrZero(this._rescc["stale-while-revalidate"]);
1870
- return Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1e3;
2011
+ return Math.round(Math.max(0, age, staleIfErrorAge, staleWhileRevalidateAge) * 1e3);
1871
2012
  }
2013
+ /**
2014
+ * If true, this cache entry is past its expiration date.
2015
+ * Note that stale cache may be useful sometimes, see `evaluateRequest()`.
2016
+ * @returns {boolean} `false` doesn't mean it's fresh nor usable
2017
+ */
1872
2018
  stale() {
1873
2019
  return this.maxAge() <= this.age();
1874
2020
  }
2021
+ /**
2022
+ * @returns {boolean} `true` if `stale-if-error` condition allows use of a stale response.
2023
+ */
1875
2024
  _useStaleIfError() {
1876
2025
  return this.maxAge() + toNumberOrZero(this._rescc["stale-if-error"]) > this.age();
1877
2026
  }
2027
+ /** See `evaluateRequest()` for a more complete solution
2028
+ * @returns {boolean} `true` if `stale-while-revalidate` is currently allowed.
2029
+ */
1878
2030
  useStaleWhileRevalidate() {
1879
- return this.maxAge() + toNumberOrZero(this._rescc["stale-while-revalidate"]) > this.age();
2031
+ const swr = toNumberOrZero(this._rescc["stale-while-revalidate"]);
2032
+ return swr > 0 && this.maxAge() + swr > this.age();
1880
2033
  }
2034
+ /**
2035
+ * Creates a `CachePolicy` instance from a serialized object.
2036
+ * @param {Object} obj - The serialized object.
2037
+ * @returns {CachePolicy} A new CachePolicy instance.
2038
+ */
1881
2039
  static fromObject(obj) {
1882
2040
  return new this(void 0, void 0, { _fromObject: obj });
1883
2041
  }
2042
+ /**
2043
+ * @param {any} obj - The serialized object.
2044
+ * @throws {Error} If already initialized or if the object is invalid.
2045
+ */
1884
2046
  _fromObject(obj) {
1885
2047
  if (this._responseTime) throw Error("Reinitialized");
1886
2048
  if (!obj || obj.v !== 1) throw Error("Invalid serialization");
@@ -1888,6 +2050,7 @@ var require_http_cache_semantics = __commonJS({
1888
2050
  this._isShared = obj.sh;
1889
2051
  this._cacheHeuristic = obj.ch;
1890
2052
  this._immutableMinTtl = obj.imm !== void 0 ? obj.imm : 24 * 3600 * 1e3;
2053
+ this._ignoreCargoCult = !!obj.icc;
1891
2054
  this._status = obj.st;
1892
2055
  this._resHeaders = obj.resh;
1893
2056
  this._rescc = obj.rescc;
@@ -1898,6 +2061,10 @@ var require_http_cache_semantics = __commonJS({
1898
2061
  this._reqHeaders = obj.reqh;
1899
2062
  this._reqcc = obj.reqcc;
1900
2063
  }
2064
+ /**
2065
+ * Serializes the `CachePolicy` instance into a JSON-serializable object.
2066
+ * @returns {Object} The serialized object.
2067
+ */
1901
2068
  toObject() {
1902
2069
  return {
1903
2070
  v: 1,
@@ -1905,6 +2072,7 @@ var require_http_cache_semantics = __commonJS({
1905
2072
  sh: this._isShared,
1906
2073
  ch: this._cacheHeuristic,
1907
2074
  imm: this._immutableMinTtl,
2075
+ icc: this._ignoreCargoCult,
1908
2076
  st: this._status,
1909
2077
  resh: this._resHeaders,
1910
2078
  rescc: this._rescc,
@@ -1922,6 +2090,8 @@ var require_http_cache_semantics = __commonJS({
1922
2090
  *
1923
2091
  * Hop by hop headers are always stripped.
1924
2092
  * Revalidation headers may be added or removed, depending on request.
2093
+ * @param {HttpRequest} incomingReq - The incoming HTTP request.
2094
+ * @returns {Record<string, string>} The headers for the revalidation request.
1925
2095
  */
1926
2096
  revalidationHeaders(incomingReq) {
1927
2097
  this._assertRequestHasHeaders(incomingReq);
@@ -1960,15 +2130,18 @@ var require_http_cache_semantics = __commonJS({
1960
2130
  * Returns {policy, modified} where modified is a boolean indicating
1961
2131
  * whether the response body has been modified, and old cached body can't be used.
1962
2132
  *
1963
- * @return {Object} {policy: CachePolicy, modified: Boolean}
2133
+ * @param {HttpRequest} request - The latest HTTP request asking for the cached entry.
2134
+ * @param {HttpResponse} response - The latest revalidation HTTP response from the origin server.
2135
+ * @returns {{policy: CachePolicy, modified: boolean, matches: boolean}} The updated policy and modification status.
2136
+ * @throws {Error} If the response headers are missing.
1964
2137
  */
1965
2138
  revalidatedPolicy(request, response) {
1966
2139
  this._assertRequestHasHeaders(request);
1967
2140
  if (this._useStaleIfError() && isErrorResponse(response)) {
1968
2141
  return {
2142
+ policy: this,
1969
2143
  modified: false,
1970
- matches: false,
1971
- policy: this
2144
+ matches: true
1972
2145
  };
1973
2146
  }
1974
2147
  if (!response || !response.headers) {
@@ -1988,9 +2161,15 @@ var require_http_cache_semantics = __commonJS({
1988
2161
  matches = true;
1989
2162
  }
1990
2163
  }
2164
+ const optionsCopy = {
2165
+ shared: this._isShared,
2166
+ cacheHeuristic: this._cacheHeuristic,
2167
+ immutableMinTimeToLive: this._immutableMinTtl,
2168
+ ignoreCargoCult: this._ignoreCargoCult
2169
+ };
1991
2170
  if (!matches) {
1992
2171
  return {
1993
- policy: new this.constructor(request, response),
2172
+ policy: new this.constructor(request, response, optionsCopy),
1994
2173
  // Client receiving 304 without body, even if it's invalid/mismatched has no option
1995
2174
  // but to reuse a cached body. We don't have a good way to tell clients to do
1996
2175
  // error recovery in such case.
@@ -2008,11 +2187,7 @@ var require_http_cache_semantics = __commonJS({
2008
2187
  headers
2009
2188
  });
2010
2189
  return {
2011
- policy: new this.constructor(request, newResponse, {
2012
- shared: this._isShared,
2013
- cacheHeuristic: this._cacheHeuristic,
2014
- immutableMinTimeToLive: this._immutableMinTtl
2015
- }),
2190
+ policy: new this.constructor(request, newResponse, optionsCopy),
2016
2191
  modified: false,
2017
2192
  matches: true
2018
2193
  };