@vercel/functions 2.2.2 → 2.2.3

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
@@ -1,5 +1,11 @@
1
1
  # @vercel/functions
2
2
 
3
+ ## 2.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Update runtime cache api to support usage during builds ([#13426](https://github.com/vercel/vercel/pull/13426))
8
+
3
9
  ## 2.2.2
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,18 @@
1
+ export declare class BuildCache {
2
+ private readonly endpoint;
3
+ private readonly headers;
4
+ private readonly onError?;
5
+ constructor({ endpoint, headers, onError, }: {
6
+ endpoint: string;
7
+ headers: Record<string, string>;
8
+ onError?: (error: Error) => void;
9
+ });
10
+ get: (key: string) => Promise<unknown>;
11
+ set: (key: string, value: unknown, options?: {
12
+ name?: string;
13
+ ttl?: number;
14
+ tags?: string[];
15
+ }) => Promise<void>;
16
+ delete: (key: string) => Promise<void>;
17
+ expireTag: (tag: string | string[]) => Promise<void>;
18
+ }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var build_client_exports = {};
20
+ __export(build_client_exports, {
21
+ BuildCache: () => BuildCache
22
+ });
23
+ module.exports = __toCommonJS(build_client_exports);
24
+ var import_index = require("./index");
25
+ class BuildCache {
26
+ constructor({
27
+ endpoint,
28
+ headers,
29
+ onError
30
+ }) {
31
+ this.get = async (key) => {
32
+ try {
33
+ const res = await fetch(`${this.endpoint}${key}`, {
34
+ headers: this.headers,
35
+ method: "GET"
36
+ });
37
+ if (res.status === 404) {
38
+ return null;
39
+ }
40
+ if (res.status === 200) {
41
+ const cacheState = res.headers.get(
42
+ import_index.HEADERS_VERCEL_CACHE_STATE
43
+ );
44
+ if (cacheState !== import_index.PkgCacheState.Fresh) {
45
+ res.body?.cancel?.();
46
+ return null;
47
+ }
48
+ return await res.json();
49
+ } else {
50
+ throw new Error(`Failed to get cache: ${res.statusText}`);
51
+ }
52
+ } catch (error) {
53
+ this.onError?.(error);
54
+ return null;
55
+ }
56
+ };
57
+ this.set = async (key, value, options) => {
58
+ try {
59
+ const optionalHeaders = {};
60
+ if (options?.ttl) {
61
+ optionalHeaders[import_index.HEADERS_VERCEL_REVALIDATE] = options.ttl.toString();
62
+ }
63
+ if (options?.tags && options.tags.length > 0) {
64
+ optionalHeaders[import_index.HEADERS_VERCEL_CACHE_TAGS] = options.tags.join(",");
65
+ }
66
+ if (options?.name) {
67
+ optionalHeaders[import_index.HEADERS_VERCEL_CACHE_ITEM_NAME] = options.name;
68
+ }
69
+ const res = await fetch(`${this.endpoint}${key}`, {
70
+ method: "POST",
71
+ headers: {
72
+ ...this.headers,
73
+ ...optionalHeaders
74
+ },
75
+ body: JSON.stringify(value)
76
+ });
77
+ if (res.status !== 200) {
78
+ throw new Error(`Failed to set cache: ${res.status} ${res.statusText}`);
79
+ }
80
+ } catch (error) {
81
+ this.onError?.(error);
82
+ }
83
+ };
84
+ this.delete = async (key) => {
85
+ try {
86
+ const res = await fetch(`${this.endpoint}${key}`, {
87
+ method: "DELETE",
88
+ headers: this.headers
89
+ });
90
+ if (res.status !== 200) {
91
+ throw new Error(`Failed to delete cache: ${res.statusText}`);
92
+ }
93
+ } catch (error) {
94
+ this.onError?.(error);
95
+ }
96
+ };
97
+ this.expireTag = async (tag) => {
98
+ try {
99
+ if (Array.isArray(tag)) {
100
+ tag = tag.join(",");
101
+ }
102
+ const res = await fetch(`${this.endpoint}revalidate?tags=${tag}`, {
103
+ method: "POST",
104
+ headers: this.headers
105
+ });
106
+ if (res.status !== 200) {
107
+ throw new Error(`Failed to revalidate tag: ${res.statusText}`);
108
+ }
109
+ } catch (error) {
110
+ this.onError?.(error);
111
+ }
112
+ };
113
+ this.endpoint = endpoint;
114
+ this.headers = headers;
115
+ this.onError = onError;
116
+ }
117
+ }
118
+ // Annotate the CommonJS export names for ESM import in node:
119
+ 0 && (module.exports = {
120
+ BuildCache
121
+ });
@@ -1,9 +1,7 @@
1
1
  import { RuntimeCache } from './types';
2
2
  export declare class InMemoryCache implements RuntimeCache {
3
3
  private cache;
4
- get(key: string, options?: {
5
- tags?: string[];
6
- }): Promise<unknown | null>;
4
+ get(key: string): Promise<unknown | null>;
7
5
  set(key: string, value: unknown, options?: {
8
6
  ttl?: number;
9
7
  tags?: string[];
@@ -25,18 +25,13 @@ class InMemoryCache {
25
25
  constructor() {
26
26
  this.cache = {};
27
27
  }
28
- async get(key, options) {
28
+ async get(key) {
29
29
  const entry = this.cache[key];
30
30
  if (entry) {
31
31
  if (entry.ttl && entry.lastModified + entry.ttl * 1e3 < Date.now()) {
32
32
  await this.delete(key);
33
33
  return null;
34
34
  }
35
- if (options?.tags) {
36
- for (const tag of options.tags) {
37
- entry.tags.add(tag);
38
- }
39
- }
40
35
  return entry.value;
41
36
  }
42
37
  return null;
package/cache/index.d.ts CHANGED
@@ -14,3 +14,14 @@ import { CacheOptions, RuntimeCache } from './types';
14
14
  * @throws {Error} If no cache is available in the context and `InMemoryCache` cannot be created.
15
15
  */
16
16
  export declare const getCache: (cacheOptions?: CacheOptions) => RuntimeCache;
17
+ export declare enum PkgCacheState {
18
+ Fresh = "fresh",
19
+ Stale = "stale",
20
+ Expired = "expired",
21
+ NotFound = "notFound",
22
+ Error = "error"
23
+ }
24
+ export declare const HEADERS_VERCEL_CACHE_STATE = "x-vercel-cache-state";
25
+ export declare const HEADERS_VERCEL_REVALIDATE = "x-vercel-revalidate";
26
+ export declare const HEADERS_VERCEL_CACHE_TAGS = "x-vercel-cache-tags";
27
+ export declare const HEADERS_VERCEL_CACHE_ITEM_NAME = "x-vercel-cache-item-name";
package/cache/index.js CHANGED
@@ -18,11 +18,17 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var cache_exports = {};
20
20
  __export(cache_exports, {
21
+ HEADERS_VERCEL_CACHE_ITEM_NAME: () => HEADERS_VERCEL_CACHE_ITEM_NAME,
22
+ HEADERS_VERCEL_CACHE_STATE: () => HEADERS_VERCEL_CACHE_STATE,
23
+ HEADERS_VERCEL_CACHE_TAGS: () => HEADERS_VERCEL_CACHE_TAGS,
24
+ HEADERS_VERCEL_REVALIDATE: () => HEADERS_VERCEL_REVALIDATE,
25
+ PkgCacheState: () => PkgCacheState,
21
26
  getCache: () => getCache
22
27
  });
23
28
  module.exports = __toCommonJS(cache_exports);
24
29
  var import_get_context = require("../get-context");
25
30
  var import_in_memory_cache = require("./in-memory-cache");
31
+ var import_build_client = require("./build-client");
26
32
  const defaultKeyHashFunction = (key) => {
27
33
  let hash = 5381;
28
34
  for (let i = 0; i < key.length; i++) {
@@ -32,31 +38,37 @@ const defaultKeyHashFunction = (key) => {
32
38
  };
33
39
  const defaultNamespaceSeparator = "$";
34
40
  let inMemoryCacheInstance = null;
41
+ let buildCacheInstance = null;
35
42
  const getCache = (cacheOptions) => {
36
43
  const resolveCache = () => {
37
- const ctxCache = (0, import_get_context.getContext)().cache;
38
- if (ctxCache)
39
- return ctxCache;
40
- if (!inMemoryCacheInstance) {
41
- inMemoryCacheInstance = new import_in_memory_cache.InMemoryCache();
42
- console.warn(
43
- "Runtime Cache unavailable in this environment. Falling back to in-memory cache."
44
+ let cache;
45
+ if ((0, import_get_context.getContext)().cache) {
46
+ cache = (0, import_get_context.getContext)().cache;
47
+ } else {
48
+ cache = getCacheImplementation(
49
+ process.env.SUSPENSE_CACHE_DEBUG === "true"
44
50
  );
45
51
  }
46
- return inMemoryCacheInstance;
52
+ return cache;
47
53
  };
54
+ return wrapWithKeyTransformation(
55
+ resolveCache,
56
+ createKeyTransformer(cacheOptions)
57
+ );
58
+ };
59
+ function createKeyTransformer(cacheOptions) {
48
60
  const hashFunction = cacheOptions?.keyHashFunction || defaultKeyHashFunction;
49
- const makeKey = (key) => {
50
- let prefix = "";
51
- if (cacheOptions?.namespace) {
52
- const namespaceSeparator = cacheOptions.namespaceSeparator || defaultNamespaceSeparator;
53
- prefix = `${cacheOptions.namespace}${namespaceSeparator}`;
54
- }
55
- return `${prefix}${hashFunction(key)}`;
61
+ return (key) => {
62
+ if (!cacheOptions?.namespace)
63
+ return hashFunction(key);
64
+ const separator = cacheOptions.namespaceSeparator || defaultNamespaceSeparator;
65
+ return `${cacheOptions.namespace}${separator}${hashFunction(key)}`;
56
66
  };
67
+ }
68
+ function wrapWithKeyTransformation(resolveCache, makeKey) {
57
69
  return {
58
- get: (key, options) => {
59
- return resolveCache().get(makeKey(key), options);
70
+ get: (key) => {
71
+ return resolveCache().get(makeKey(key));
60
72
  },
61
73
  set: (key, value, options) => {
62
74
  return resolveCache().set(makeKey(key), value, options);
@@ -68,8 +80,62 @@ const getCache = (cacheOptions) => {
68
80
  return resolveCache().expireTag(tag);
69
81
  }
70
82
  };
71
- };
83
+ }
84
+ function getCacheImplementation(debug) {
85
+ if (!inMemoryCacheInstance) {
86
+ inMemoryCacheInstance = new import_in_memory_cache.InMemoryCache();
87
+ }
88
+ if (process.env.RUNTIME_CACHE_DISABLE_BUILD_CACHE === "true") {
89
+ debug && console.log("Using InMemoryCache as build cache is disabled");
90
+ return inMemoryCacheInstance;
91
+ }
92
+ const { RUNTIME_CACHE_ENDPOINT, RUNTIME_CACHE_HEADERS } = process.env;
93
+ if (debug) {
94
+ console.log("Runtime cache environment variables:", {
95
+ RUNTIME_CACHE_ENDPOINT,
96
+ RUNTIME_CACHE_HEADERS
97
+ });
98
+ }
99
+ if (!RUNTIME_CACHE_ENDPOINT || !RUNTIME_CACHE_HEADERS) {
100
+ console.warn(
101
+ "Runtime Cache unavailable in this environment. Falling back to in-memory cache."
102
+ );
103
+ return inMemoryCacheInstance;
104
+ }
105
+ if (!buildCacheInstance) {
106
+ let parsedHeaders = {};
107
+ try {
108
+ parsedHeaders = JSON.parse(RUNTIME_CACHE_HEADERS);
109
+ } catch (e) {
110
+ console.error("Failed to parse RUNTIME_CACHE_HEADERS:", e);
111
+ return inMemoryCacheInstance;
112
+ }
113
+ buildCacheInstance = new import_build_client.BuildCache({
114
+ endpoint: RUNTIME_CACHE_ENDPOINT,
115
+ headers: parsedHeaders,
116
+ onError: (error) => console.error(error)
117
+ });
118
+ }
119
+ return buildCacheInstance;
120
+ }
121
+ var PkgCacheState = /* @__PURE__ */ ((PkgCacheState2) => {
122
+ PkgCacheState2["Fresh"] = "fresh";
123
+ PkgCacheState2["Stale"] = "stale";
124
+ PkgCacheState2["Expired"] = "expired";
125
+ PkgCacheState2["NotFound"] = "notFound";
126
+ PkgCacheState2["Error"] = "error";
127
+ return PkgCacheState2;
128
+ })(PkgCacheState || {});
129
+ const HEADERS_VERCEL_CACHE_STATE = "x-vercel-cache-state";
130
+ const HEADERS_VERCEL_REVALIDATE = "x-vercel-revalidate";
131
+ const HEADERS_VERCEL_CACHE_TAGS = "x-vercel-cache-tags";
132
+ const HEADERS_VERCEL_CACHE_ITEM_NAME = "x-vercel-cache-item-name";
72
133
  // Annotate the CommonJS export names for ESM import in node:
73
134
  0 && (module.exports = {
135
+ HEADERS_VERCEL_CACHE_ITEM_NAME,
136
+ HEADERS_VERCEL_CACHE_STATE,
137
+ HEADERS_VERCEL_CACHE_TAGS,
138
+ HEADERS_VERCEL_REVALIDATE,
139
+ PkgCacheState,
74
140
  getCache
75
141
  });
package/cache/types.d.ts CHANGED
@@ -13,13 +13,9 @@ export interface RuntimeCache {
13
13
  * Retrieves a value from the cache.
14
14
  *
15
15
  * @param {string} key - The key of the value to retrieve.
16
- * @param {Object} [options] - Optional settings for the cache entry.
17
- * @param {string[]} [options.tags] - Optional tags to associate wit the cache entry.
18
16
  * @returns {Promise<unknown | null>} A promise that resolves to the value, or null if not found.
19
17
  */
20
- get: (key: string, options?: {
21
- tags?: string[];
22
- }) => Promise<unknown | null>;
18
+ get: (key: string) => Promise<unknown | null>;
23
19
  /**
24
20
  * Sets a value in the cache.
25
21
  *
@@ -67,27 +67,25 @@ A promise that resolves when the cache entries expiration request is received.
67
67
 
68
68
  #### Defined in
69
69
 
70
- [packages/functions/src/cache/types.ts:46](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L46)
70
+ [packages/functions/src/cache/types.ts:44](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L44)
71
71
 
72
72
  ---
73
73
 
74
74
  ### get
75
75
 
76
- • **get**: (`key`: `string`, `options?`: { `tags?`: `string`[] }) => [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`unknown`\>
76
+ • **get**: (`key`: `string`) => [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`unknown`\>
77
77
 
78
78
  #### Type declaration
79
79
 
80
- ▸ (`key`, `options?`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`unknown`\>
80
+ ▸ (`key`): [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<`unknown`\>
81
81
 
82
82
  Retrieves a value from the cache.
83
83
 
84
84
  ##### Parameters
85
85
 
86
- | Name | Type | Description |
87
- | :-------------- | :--------- | :---------------------------------------------- |
88
- | `key` | `string` | The key of the value to retrieve. |
89
- | `options?` | `Object` | Optional settings for the cache entry. |
90
- | `options.tags?` | `string`[] | Optional tags to associate wit the cache entry. |
86
+ | Name | Type | Description |
87
+ | :---- | :------- | :-------------------------------- |
88
+ | `key` | `string` | The key of the value to retrieve. |
91
89
 
92
90
  ##### Returns
93
91
 
@@ -97,7 +95,7 @@ A promise that resolves to the value, or null if not found.
97
95
 
98
96
  #### Defined in
99
97
 
100
- [packages/functions/src/cache/types.ts:21](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L21)
98
+ [packages/functions/src/cache/types.ts:19](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L19)
101
99
 
102
100
  ---
103
101
 
@@ -130,4 +128,4 @@ A promise that resolves when the value is set.
130
128
 
131
129
  #### Defined in
132
130
 
133
- [packages/functions/src/cache/types.ts:34](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L34)
131
+ [packages/functions/src/cache/types.ts:32](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/types.ts#L32)
@@ -99,7 +99,7 @@ An instance of the Vercel Runtime Cache.
99
99
 
100
100
  #### Defined in
101
101
 
102
- [packages/functions/src/cache/index.ts:32](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/index.ts#L32)
102
+ [packages/functions/src/cache/index.ts:33](https://github.com/vercel/vercel/blob/main/packages/functions/src/cache/index.ts#L33)
103
103
 
104
104
  ---
105
105
 
package/package.json CHANGED
@@ -26,7 +26,7 @@
26
26
  "require": "./middleware.js"
27
27
  }
28
28
  },
29
- "version": "2.2.2",
29
+ "version": "2.2.3",
30
30
  "repository": {
31
31
  "directory": "packages/functions",
32
32
  "type": "git",