@netlify/cache 1.1.0 → 1.3.0

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/dist/main.js CHANGED
@@ -0,0 +1,270 @@
1
+ import {
2
+ CacheStatus,
3
+ NetlifyCacheId,
4
+ NetlifyCacheTag,
5
+ NetlifyCdnCacheControl,
6
+ NetlifyVary
7
+ } from "./chunk-I5FZDZ6V.js";
8
+
9
+ // src/cache-headers/validation.ts
10
+ var ensureArray = (value) => Array.isArray(value) ? value : [value];
11
+ var requireArrayOfStrings = (name, value) => {
12
+ if (!Array.isArray(value) || value.some((part) => typeof part !== "string" || part.length === 0)) {
13
+ throw new TypeError(`'${name}' must be an array of non-empty strings.`);
14
+ }
15
+ return value;
16
+ };
17
+ var requireArrayOfStringsWithNesting = (name, value, joiner) => {
18
+ if (!Array.isArray(value)) {
19
+ throw new TypeError(`'${name}' must be an array.`);
20
+ }
21
+ return value.map((part, index) => {
22
+ if (typeof part === "string") {
23
+ return part;
24
+ }
25
+ return requireArrayOfStrings(`${name}[${index}]`, part).join(joiner);
26
+ });
27
+ };
28
+ var requirePositiveInteger = (name, value) => {
29
+ const number = Number.parseFloat(value);
30
+ if (Number.isNaN(number) || !Number.isInteger(number) || number < 0 || number === Number.POSITIVE_INFINITY) {
31
+ throw new TypeError(`'${name}' must be a positive integer number.`);
32
+ }
33
+ return number;
34
+ };
35
+
36
+ // src/cache-headers/cache-headers.ts
37
+ var ONE_YEAR = 60 * 24 * 365;
38
+ var cacheHeaders = (cacheSettings) => {
39
+ const { durable, overrideDeployRevalidation: id, tags, ttl, swr, vary } = cacheSettings;
40
+ const headers = {};
41
+ const cacheControlDirectives = [];
42
+ if (ttl) {
43
+ const ttlValue = requirePositiveInteger("ttl", ttl);
44
+ if (ttlValue > 0) {
45
+ cacheControlDirectives.push(`s-maxage=${ttlValue}`);
46
+ }
47
+ }
48
+ if (swr) {
49
+ const swrValue = swr === true ? ONE_YEAR : requirePositiveInteger("swr", swr);
50
+ if (swrValue > 0) {
51
+ cacheControlDirectives.push(`stale-while-revalidate=${swrValue}`);
52
+ }
53
+ }
54
+ if (cacheControlDirectives.length > 0) {
55
+ if (durable) {
56
+ cacheControlDirectives.push("durable");
57
+ }
58
+ headers[NetlifyCdnCacheControl] = cacheControlDirectives.join(",");
59
+ }
60
+ if (tags) {
61
+ headers[NetlifyCacheTag] = requireArrayOfStrings("tags", tags).join(",");
62
+ }
63
+ const netlifyVary = getNetlifyVary(vary);
64
+ if (netlifyVary) {
65
+ headers[NetlifyVary] = netlifyVary;
66
+ }
67
+ if (id) {
68
+ headers[NetlifyCacheId] = requireArrayOfStrings("id", ensureArray(id)).join(",");
69
+ }
70
+ return headers;
71
+ };
72
+ var getNetlifyVary = (varyOptions) => {
73
+ if (!varyOptions) {
74
+ return null;
75
+ }
76
+ const { cookie, country, header, language, query } = varyOptions;
77
+ const directives = [];
78
+ if (cookie) {
79
+ directives.push(`cookie=${requireArrayOfStrings("cookie", ensureArray(cookie)).join("|")}`);
80
+ }
81
+ if (country) {
82
+ directives.push(`country=${requireArrayOfStringsWithNesting("country", ensureArray(country), "+").join("|")}`);
83
+ }
84
+ if (header) {
85
+ directives.push(`header=${requireArrayOfStrings("header", ensureArray(header)).join("|")}`);
86
+ }
87
+ if (language) {
88
+ directives.push(`language=${requireArrayOfStringsWithNesting("language", ensureArray(language), "+").join("|")}`);
89
+ }
90
+ if (query) {
91
+ if (query === true) {
92
+ directives.push(`query`);
93
+ } else {
94
+ directives.push(`query=${requireArrayOfStrings("query", ensureArray(query)).join("|")}`);
95
+ }
96
+ }
97
+ if (directives.length === 0) {
98
+ return null;
99
+ }
100
+ return directives.join(",");
101
+ };
102
+ var applyHeaders = (subject, headersObject) => {
103
+ for (const name in headersObject) {
104
+ if (name === NetlifyCdnCacheControl) {
105
+ subject.set(name, headersObject[name]);
106
+ } else {
107
+ subject.append(name, headersObject[name]);
108
+ }
109
+ }
110
+ };
111
+ var setCacheHeaders = (response, cacheSettings) => {
112
+ if (!(response instanceof Response)) {
113
+ throw new TypeError("Input must be a Response object.");
114
+ }
115
+ const newResponse = new Response(response.body, response);
116
+ applyHeaders(newResponse.headers, cacheHeaders(cacheSettings));
117
+ return newResponse;
118
+ };
119
+
120
+ // src/cache-status/cache-status.ts
121
+ var CACHE_DURABLE = "netlify durable";
122
+ var CACHE_EDGE = "netlify edge";
123
+ var parseCacheStatusValue = (value) => {
124
+ const parts = value.split(";").map((part) => part.trim());
125
+ const [namePart, ...attributeParts] = parts;
126
+ const name = (namePart ?? "").replace(/"/g, "").toLowerCase();
127
+ const attributes = attributeParts.reduce((acc, part) => {
128
+ const [key, value2 = ""] = part.split("=");
129
+ return {
130
+ ...acc,
131
+ [key]: value2
132
+ };
133
+ }, {});
134
+ return {
135
+ attributes,
136
+ name
137
+ };
138
+ };
139
+ var parseCacheStatusValues = (cacheStatusValues) => {
140
+ const cacheStatus = {
141
+ hit: false,
142
+ caches: {}
143
+ };
144
+ for (const value of cacheStatusValues.split(",")) {
145
+ const { attributes, name } = parseCacheStatusValue(value);
146
+ if (name === CACHE_EDGE) {
147
+ const hit = attributes.hit !== void 0;
148
+ cacheStatus.caches.edge = {
149
+ hit,
150
+ fresh: hit && attributes.fwd !== "stale"
151
+ };
152
+ cacheStatus.hit = cacheStatus.hit || hit;
153
+ continue;
154
+ }
155
+ if (name === CACHE_DURABLE) {
156
+ let ttl = 0;
157
+ if (attributes.ttl !== void 0) {
158
+ const parsedTTL = Number.parseInt(attributes.ttl);
159
+ if (!Number.isNaN(parsedTTL)) {
160
+ ttl = parsedTTL;
161
+ }
162
+ }
163
+ const hit = attributes.hit !== void 0;
164
+ cacheStatus.caches.durable = {
165
+ hit,
166
+ fresh: hit && attributes.fwd !== "stale",
167
+ stored: attributes.stored === "true",
168
+ ttl
169
+ };
170
+ cacheStatus.hit = cacheStatus.hit || hit;
171
+ continue;
172
+ }
173
+ }
174
+ if (Object.keys(cacheStatus.caches).length === 0) {
175
+ return null;
176
+ }
177
+ return cacheStatus;
178
+ };
179
+ var getCacheStatus = (input) => {
180
+ if (typeof input === "string") {
181
+ return parseCacheStatusValues(input);
182
+ }
183
+ if (input instanceof Headers) {
184
+ return parseCacheStatusValues(input.get(CacheStatus) ?? "");
185
+ }
186
+ if (input instanceof Response) {
187
+ return parseCacheStatusValues(input.headers.get(CacheStatus) ?? "");
188
+ }
189
+ throw new TypeError("`getCacheStatus` expects a string, a `Headers` object or a `Response` object.");
190
+ };
191
+
192
+ // src/fetchwithcache.ts
193
+ var requestInitOptions = [
194
+ "method",
195
+ "keepalive",
196
+ "headers",
197
+ "body",
198
+ "redirect",
199
+ "integrity",
200
+ "signal",
201
+ "credentials",
202
+ "mode",
203
+ "referrer",
204
+ "referrerPolicy",
205
+ "window",
206
+ "dispatcher",
207
+ "duplex"
208
+ ];
209
+ var isRequestInit = (input) => {
210
+ if (typeof input !== "object") {
211
+ return false;
212
+ }
213
+ for (const property of requestInitOptions) {
214
+ if (property in input) {
215
+ return true;
216
+ }
217
+ }
218
+ return false;
219
+ };
220
+ var fetchWithCache = async (request, optionsOrCacheSettings, cacheOptionsParam) => {
221
+ let cacheOptions;
222
+ let requestInit;
223
+ if (isRequestInit(optionsOrCacheSettings)) {
224
+ cacheOptions = cacheOptionsParam || {};
225
+ requestInit = optionsOrCacheSettings;
226
+ } else {
227
+ cacheOptions = optionsOrCacheSettings || {};
228
+ requestInit = {};
229
+ }
230
+ let method;
231
+ if (request instanceof Request) {
232
+ method = request.method;
233
+ } else {
234
+ method = requestInit?.method;
235
+ }
236
+ if (method && method?.toLowerCase() !== "get") {
237
+ throw new TypeError("`fetchWithCache` only supports GET requests.");
238
+ }
239
+ let cache;
240
+ const { cache: cacheParam, onCachePut, ...cacheSettings } = cacheOptions;
241
+ if (cacheParam) {
242
+ if (typeof cacheParam === "string") {
243
+ cache = await caches.open(cacheParam);
244
+ } else if (cacheParam instanceof Cache) {
245
+ cache = cacheParam;
246
+ } else {
247
+ throw new TypeError("`cache` must be a string representing the cache name or an instance of `Cache`.");
248
+ }
249
+ } else {
250
+ cache = await caches.open("");
251
+ }
252
+ const cached = await cache.match(request);
253
+ if (cached) {
254
+ return cached;
255
+ }
256
+ const fresh = await fetch(request, requestInit);
257
+ const responseForCache = setCacheHeaders(fresh.clone(), cacheSettings);
258
+ const cachePut = cache.put(request, responseForCache);
259
+ if (onCachePut) {
260
+ await onCachePut(cachePut);
261
+ } else {
262
+ await cachePut;
263
+ }
264
+ return fresh;
265
+ };
266
+ export {
267
+ fetchWithCache,
268
+ getCacheStatus,
269
+ setCacheHeaders
270
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/cache",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "TypeScript utilities for interacting with the Netlify cache",
5
5
  "type": "module",
6
6
  "engines": {
@@ -56,16 +56,18 @@
56
56
  "test:dev:vitest:watch": "vitest watch",
57
57
  "test:ci:vitest": "vitest run"
58
58
  },
59
- "keywords": [],
59
+ "keywords": [
60
+ "netlify",
61
+ "cdn",
62
+ "cache",
63
+ "cachestorage"
64
+ ],
60
65
  "license": "MIT",
61
66
  "repository": "netlify/cache",
62
67
  "bugs": {
63
68
  "url": "https://github.com/netlify/cache/issues"
64
69
  },
65
70
  "author": "Netlify Inc.",
66
- "directories": {
67
- "test": "test"
68
- },
69
71
  "devDependencies": {
70
72
  "npm-run-all2": "^7.0.2",
71
73
  "semver": "^7.5.3",