@opennextjs/aws 3.4.2 → 3.5.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.
Files changed (82) hide show
  1. package/dist/adapters/cache.d.ts +2 -61
  2. package/dist/adapters/cache.js +68 -34
  3. package/dist/adapters/config/index.d.ts +1 -0
  4. package/dist/adapters/config/index.js +3 -1
  5. package/dist/adapters/config/util.d.ts +2 -1
  6. package/dist/adapters/config/util.js +13 -3
  7. package/dist/adapters/dynamo-provider.js +8 -0
  8. package/dist/adapters/edge-adapter.js +4 -10
  9. package/dist/adapters/image-optimization-adapter.d.ts +3 -2
  10. package/dist/adapters/image-optimization-adapter.js +3 -3
  11. package/dist/adapters/middleware.js +12 -8
  12. package/dist/build/compileConfig.js +1 -1
  13. package/dist/build/compileTagCacheProvider.js +1 -0
  14. package/dist/build/constant.d.ts +1 -0
  15. package/dist/build/constant.js +2 -0
  16. package/dist/build/copyTracedFiles.d.ts +10 -1
  17. package/dist/build/copyTracedFiles.js +22 -12
  18. package/dist/build/createAssets.d.ts +3 -1
  19. package/dist/build/createAssets.js +2 -2
  20. package/dist/build/createMiddleware.js +18 -5
  21. package/dist/build/createServerBundle.js +7 -1
  22. package/dist/build/edge/createEdgeBundle.js +14 -12
  23. package/dist/build/generateOutput.js +4 -6
  24. package/dist/build/middleware/buildNodeMiddleware.d.ts +3 -0
  25. package/dist/build/middleware/buildNodeMiddleware.js +97 -0
  26. package/dist/core/createMainHandler.js +0 -1
  27. package/dist/core/edgeFunctionHandler.js +3 -1
  28. package/dist/core/nodeMiddlewareHandler.d.ts +4 -0
  29. package/dist/core/nodeMiddlewareHandler.js +25 -0
  30. package/dist/core/requestHandler.d.ts +3 -2
  31. package/dist/core/requestHandler.js +58 -25
  32. package/dist/core/routing/cacheInterceptor.js +7 -6
  33. package/dist/core/routing/i18n/index.d.ts +2 -0
  34. package/dist/core/routing/i18n/index.js +1 -1
  35. package/dist/core/routing/matcher.js +13 -12
  36. package/dist/core/routing/middleware.js +14 -29
  37. package/dist/core/routing/queue.d.ts +1 -0
  38. package/dist/core/routing/queue.js +41 -0
  39. package/dist/core/routing/util.d.ts +12 -3
  40. package/dist/core/routing/util.js +24 -50
  41. package/dist/core/routingHandler.d.ts +2 -1
  42. package/dist/core/routingHandler.js +10 -4
  43. package/dist/core/util.d.ts +1 -4
  44. package/dist/core/util.js +7 -15
  45. package/dist/overrides/converters/aws-apigw-v1.js +4 -3
  46. package/dist/overrides/converters/aws-apigw-v2.js +4 -3
  47. package/dist/overrides/converters/aws-cloudfront.js +6 -4
  48. package/dist/overrides/converters/edge.js +1 -10
  49. package/dist/overrides/converters/node.js +10 -8
  50. package/dist/overrides/converters/utils.d.ts +7 -0
  51. package/dist/overrides/converters/utils.js +9 -0
  52. package/dist/overrides/imageLoader/s3-lite.d.ts +3 -0
  53. package/dist/overrides/imageLoader/s3-lite.js +61 -0
  54. package/dist/overrides/tagCache/dummy.js +1 -0
  55. package/dist/overrides/tagCache/dynamodb-lite.js +1 -0
  56. package/dist/overrides/tagCache/dynamodb-nextMode.d.ts +7 -0
  57. package/dist/overrides/tagCache/dynamodb-nextMode.js +119 -0
  58. package/dist/overrides/tagCache/dynamodb.js +1 -0
  59. package/dist/overrides/tagCache/fs-dev.js +1 -0
  60. package/dist/overrides/wrappers/aws-lambda-streaming.js +1 -1
  61. package/dist/overrides/wrappers/aws-lambda.js +3 -1
  62. package/dist/overrides/wrappers/cloudflare-edge.js +3 -2
  63. package/dist/overrides/wrappers/cloudflare-node.js +5 -8
  64. package/dist/overrides/wrappers/dummy.js +2 -2
  65. package/dist/overrides/wrappers/express-dev.js +4 -4
  66. package/dist/overrides/wrappers/node.js +2 -2
  67. package/dist/plugins/edge.d.ts +1 -3
  68. package/dist/plugins/edge.js +4 -11
  69. package/dist/plugins/externalMiddleware.d.ts +2 -0
  70. package/dist/plugins/externalMiddleware.js +10 -0
  71. package/dist/plugins/resolve.js +2 -2
  72. package/dist/types/cache.d.ts +34 -4
  73. package/dist/types/global.d.ts +19 -31
  74. package/dist/types/next-types.d.ts +13 -0
  75. package/dist/types/open-next.d.ts +12 -5
  76. package/dist/types/overrides.d.ts +72 -6
  77. package/dist/utils/cache.d.ts +3 -0
  78. package/dist/utils/cache.js +32 -0
  79. package/dist/utils/promise.d.ts +3 -1
  80. package/dist/utils/promise.js +18 -11
  81. package/dist/utils/regex.js +1 -1
  82. package/package.json +5 -4
@@ -1,6 +1,6 @@
1
1
  import type { Readable } from "node:stream";
2
2
  import type { Meta } from "./cache";
3
- import type { BaseEventOrResult, BaseOverride, InternalEvent, InternalResult, Origin, ResolvedRoute, StreamCreator } from "./open-next";
3
+ import type { BaseEventOrResult, BaseOverride, InternalEvent, InternalResult, Origin, ResolvedRoute, StreamCreator, WaitUntil } from "./open-next";
4
4
  export interface QueueMessage {
5
5
  MessageDeduplicationId: string;
6
6
  MessageBody: {
@@ -32,12 +32,24 @@ export type CachedFile = {
32
32
  body: string;
33
33
  meta?: Meta;
34
34
  };
35
- export type FetchCache = Object;
35
+ export type CachedFetchValue = {
36
+ kind: "FETCH";
37
+ data: {
38
+ headers: {
39
+ [k: string]: string;
40
+ };
41
+ body: string;
42
+ url: string;
43
+ status?: number;
44
+ tags?: string[];
45
+ };
46
+ tags?: string[];
47
+ };
36
48
  export type WithLastModified<T> = {
37
49
  lastModified?: number;
38
50
  value?: T;
39
51
  };
40
- export type CacheValue<IsFetch extends boolean> = (IsFetch extends true ? FetchCache : CachedFile) & {
52
+ export type CacheValue<IsFetch extends boolean> = (IsFetch extends true ? CachedFetchValue : CachedFile) & {
41
53
  revalidate?: number | false;
42
54
  };
43
55
  export type IncrementalCache = {
@@ -46,7 +58,57 @@ export type IncrementalCache = {
46
58
  delete(key: string): Promise<void>;
47
59
  name: string;
48
60
  };
49
- export type TagCache = {
61
+ type BaseTagCache = {
62
+ name: string;
63
+ };
64
+ /**
65
+ * On get :
66
+ We have to check for every tag (after reading the incremental cache) that they have not been revalidated.
67
+
68
+ In DynamoDB, this would require 1 GetItem per tag (including internal one), more realistically 1 BatchGetItem per get (In terms of pricing, it would be billed as multiple single GetItem)
69
+
70
+ On set :
71
+ We don't have to do anything here
72
+
73
+ On revalidateTag for each tag :
74
+ We have to update a single entry for this tag
75
+
76
+ Pros :
77
+ - No need to prepopulate DDB
78
+ - Very little write
79
+
80
+ Cons :
81
+ - Might be slower on read
82
+ - One page request (i.e. GET request) could require to check a lot of tags (And some of them multiple time when used with the fetch cache)
83
+ - Almost impossible to do automatic cdn revalidation by itself
84
+ */
85
+ export type NextModeTagCache = BaseTagCache & {
86
+ mode: "nextMode";
87
+ hasBeenRevalidated(tags: string[], lastModified?: number): Promise<boolean>;
88
+ writeTags(tags: string[]): Promise<void>;
89
+ getPathsByTags?: (tags: string[]) => Promise<string[]>;
90
+ };
91
+ /**
92
+ * On get :
93
+ We just check for the cache key in the tag cache. If it has been revalidated we just return null, otherwise we continue
94
+
95
+ On set :
96
+ We have to write both the incremental cache and check the tag cache for non existing tag/key combination. For non existing tag/key combination, we have to add them
97
+
98
+ On revalidateTag for each tag :
99
+ We have to update every possible combination for the requested tag
100
+
101
+ Pros :
102
+ - Very fast on read
103
+ - Only one query per get (On DynamoDB it's a lot cheaper)
104
+ - Can allow for automatic cdn invalidation on revalidateTag
105
+
106
+ Cons :
107
+ - Lots of write on set and revalidateTag
108
+ - Needs to be prepopulated at build time to work properly
109
+ */
110
+ export type OriginalTagCache = BaseTagCache & {
111
+ mode?: "original";
50
112
  getByTag(tag: string): Promise<string[]>;
51
113
  getByPath(path: string): Promise<string[]>;
52
114
  getLastModified(path: string, lastModified?: number): Promise<number>;
@@ -55,15 +117,19 @@ export type TagCache = {
55
117
  path: string;
56
118
  revalidatedAt?: number;
57
119
  }[]): Promise<void>;
58
- name: string;
59
120
  };
121
+ export type TagCache = NextModeTagCache | OriginalTagCache;
60
122
  export type WrapperHandler<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = (handler: OpenNextHandler<E, R>, converter: Converter<E, R>) => Promise<(...args: any[]) => any>;
61
123
  export type Wrapper<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = BaseOverride & {
62
124
  wrapper: WrapperHandler<E, R>;
63
125
  supportStreaming: boolean;
64
126
  edgeRuntime?: boolean;
65
127
  };
66
- export type OpenNextHandler<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = (event: E, responseStream?: StreamCreator) => Promise<R>;
128
+ export type OpenNextHandlerOptions = {
129
+ streamCreator?: StreamCreator;
130
+ waitUntil?: WaitUntil;
131
+ };
132
+ export type OpenNextHandler<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = (event: E, options?: OpenNextHandlerOptions) => Promise<R>;
67
133
  export type Converter<E extends BaseEventOrResult = InternalEvent, R extends BaseEventOrResult = InternalResult> = BaseOverride & {
68
134
  convertFrom: (event: any) => Promise<E>;
69
135
  convertTo: (result: R, originalRequest?: any) => Promise<any>;
@@ -0,0 +1,3 @@
1
+ import type { CacheValue, WithLastModified } from "../types/overrides";
2
+ export declare function hasBeenRevalidated(key: string, tags: string[], cacheEntry: WithLastModified<CacheValue<any>>): Promise<boolean>;
3
+ export declare function getTagsFromValue(value?: CacheValue<false>): string[];
@@ -0,0 +1,32 @@
1
+ export async function hasBeenRevalidated(key, tags, cacheEntry) {
2
+ if (globalThis.openNextConfig.dangerous?.disableTagCache) {
3
+ return false;
4
+ }
5
+ const value = cacheEntry.value;
6
+ if (!value) {
7
+ // We should never reach this point
8
+ return true;
9
+ }
10
+ if ("type" in cacheEntry && cacheEntry.type === "page") {
11
+ return false;
12
+ }
13
+ const lastModified = cacheEntry.lastModified ?? Date.now();
14
+ if (globalThis.tagCache.mode === "nextMode") {
15
+ return await globalThis.tagCache.hasBeenRevalidated(tags, lastModified);
16
+ }
17
+ // TODO: refactor this, we should introduce a new method in the tagCache interface so that both implementations use hasBeenRevalidated
18
+ const _lastModified = await globalThis.tagCache.getLastModified(key, lastModified);
19
+ return _lastModified === -1;
20
+ }
21
+ export function getTagsFromValue(value) {
22
+ if (!value) {
23
+ return [];
24
+ }
25
+ // The try catch is necessary for older version of next.js that may fail on this
26
+ try {
27
+ return value.meta?.headers?.["x-next-cache-tags"]?.split(",") ?? [];
28
+ }
29
+ catch (e) {
30
+ return [];
31
+ }
32
+ }
@@ -1,3 +1,4 @@
1
+ import type { WaitUntil } from "../types/open-next";
1
2
  /**
2
3
  * A `Promise.withResolvers` implementation that exposes the `resolve` and
3
4
  * `reject` functions on a `Promise`.
@@ -16,6 +17,7 @@ export declare class DetachedPromiseRunner {
16
17
  add<T>(promise: Promise<T>): void;
17
18
  await(): Promise<void>;
18
19
  }
19
- export declare function runWithOpenNextRequestContext<T>({ isISRRevalidation }: {
20
+ export declare function runWithOpenNextRequestContext<T>({ isISRRevalidation, waitUntil, }: {
20
21
  isISRRevalidation: boolean;
22
+ waitUntil?: WaitUntil;
21
23
  }, fn: () => Promise<T>): Promise<T>;
@@ -47,23 +47,22 @@ export class DetachedPromiseRunner {
47
47
  }
48
48
  }
49
49
  async function awaitAllDetachedPromise() {
50
- const promisesToAwait = globalThis.__openNextAls.getStore()?.pendingPromiseRunner.await() ??
51
- Promise.resolve();
52
- if (globalThis.openNextWaitUntil) {
53
- globalThis.openNextWaitUntil(promisesToAwait);
50
+ const store = globalThis.__openNextAls.getStore();
51
+ const promisesToAwait = store?.pendingPromiseRunner.await() ?? Promise.resolve();
52
+ if (store?.waitUntil) {
53
+ store.waitUntil(promisesToAwait);
54
54
  return;
55
55
  }
56
56
  await promisesToAwait;
57
57
  }
58
58
  function provideNextAfterProvider() {
59
- /** This should be considered unstable until `unstable_after` is stablized. */
60
59
  const NEXT_REQUEST_CONTEXT_SYMBOL = Symbol.for("@next/request-context");
61
60
  // This is needed by some lib that relies on the vercel request context to properly await stuff.
62
61
  // Remove this when vercel builder is updated to provide '@next/request-context'.
63
62
  const VERCEL_REQUEST_CONTEXT_SYMBOL = Symbol.for("@vercel/request-context");
64
- const openNextStoreContext = globalThis.__openNextAls.getStore();
65
- const waitUntil = globalThis.openNextWaitUntil ??
66
- ((promise) => openNextStoreContext?.pendingPromiseRunner.add(promise));
63
+ const store = globalThis.__openNextAls.getStore();
64
+ const waitUntil = store?.waitUntil ??
65
+ ((promise) => store?.pendingPromiseRunner.add(promise));
67
66
  const nextAfterContext = {
68
67
  get: () => ({
69
68
  waitUntil,
@@ -78,15 +77,23 @@ function provideNextAfterProvider() {
78
77
  globalThis[VERCEL_REQUEST_CONTEXT_SYMBOL] = nextAfterContext;
79
78
  }
80
79
  }
81
- export function runWithOpenNextRequestContext({ isISRRevalidation }, fn) {
80
+ export function runWithOpenNextRequestContext({ isISRRevalidation, waitUntil, }, fn) {
82
81
  return globalThis.__openNextAls.run({
83
82
  requestId: Math.random().toString(36),
84
83
  pendingPromiseRunner: new DetachedPromiseRunner(),
85
84
  isISRRevalidation,
85
+ waitUntil,
86
86
  }, async () => {
87
87
  provideNextAfterProvider();
88
- const result = await fn();
89
- await awaitAllDetachedPromise();
88
+ let result;
89
+ try {
90
+ result = await fn();
91
+ // We always await all detached promises before returning the result
92
+ // However we don't want to catch errors here, we want to let the parent handle it
93
+ }
94
+ finally {
95
+ await awaitAllDetachedPromise();
96
+ }
90
97
  return result;
91
98
  });
92
99
  }
@@ -10,7 +10,7 @@
10
10
  * getCrossPlatformPathRegex(String.raw`\./middleware\.(mjs|cjs)`, { escape: false })
11
11
  * ```
12
12
  */
13
- export function getCrossPlatformPathRegex(regex, { escape: shouldEscape = true, flags = "g" } = {}) {
13
+ export function getCrossPlatformPathRegex(regex, { escape: shouldEscape = true, flags = "" } = {}) {
14
14
  const newExpr = (shouldEscape ? regex.replace(/([[\]().*+?^$|{}\\])/g, "\\$1") : regex).replaceAll("/", String.raw `(?:\/|\\)`);
15
15
  return new RegExp(newExpr, flags);
16
16
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "access": "public"
4
4
  },
5
5
  "name": "@opennextjs/aws",
6
- "version": "3.4.2",
6
+ "version": "3.5.0",
7
7
  "bin": {
8
8
  "open-next": "./dist/index.js"
9
9
  },
@@ -13,7 +13,10 @@
13
13
  "homepage": "https://opennext.js.org/aws",
14
14
  "main": "./dist/index.js",
15
15
  "exports": {
16
- "./*": "./dist/*"
16
+ "./*": {
17
+ "default": "./dist/*",
18
+ "types": "./dist/*.d.ts"
19
+ }
17
20
  },
18
21
  "typesVersions": {
19
22
  "*": {
@@ -35,7 +38,6 @@
35
38
  "@aws-sdk/client-lambda": "^3.398.0",
36
39
  "@aws-sdk/client-s3": "^3.398.0",
37
40
  "@aws-sdk/client-sqs": "^3.398.0",
38
- "@esbuild-plugins/node-resolve": "0.2.2",
39
41
  "@node-minify/core": "^8.0.6",
40
42
  "@node-minify/terser": "^8.0.6",
41
43
  "@tsconfig/node18": "^1.0.1",
@@ -44,7 +46,6 @@
44
46
  "esbuild": "0.19.2",
45
47
  "express": "5.0.1",
46
48
  "path-to-regexp": "^6.3.0",
47
- "promise.series": "^0.2.0",
48
49
  "urlpattern-polyfill": "^10.0.0"
49
50
  },
50
51
  "devDependencies": {