@opennextjs/cloudflare 1.2.1 → 1.3.1
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/cli/args.d.ts +2 -0
- package/dist/cli/args.js +37 -19
- package/dist/cli/build/build.d.ts +2 -2
- package/dist/cli/build/build.js +3 -0
- package/dist/cli/build/bundle-server.d.ts +1 -1
- package/dist/cli/build/bundle-server.js +4 -7
- package/dist/cli/build/open-next/compile-images.d.ts +5 -0
- package/dist/cli/build/open-next/compile-images.js +29 -0
- package/dist/cli/build/open-next/createServerBundle.js +0 -1
- package/dist/cli/build/patches/plugins/next-server.d.ts +0 -2
- package/dist/cli/build/patches/plugins/next-server.js +0 -19
- package/dist/cli/build/{patches/investigated → utils}/copy-package-cli-files.js +1 -1
- package/dist/cli/build/utils/index.d.ts +1 -1
- package/dist/cli/build/utils/index.js +1 -1
- package/dist/cli/build/utils/test-patch.d.ts +9 -0
- package/dist/cli/build/utils/test-patch.js +14 -0
- package/dist/cli/build/utils/workerd.js +3 -1
- package/dist/cli/templates/images.d.ts +24 -0
- package/dist/cli/templates/images.js +82 -0
- package/dist/cli/templates/worker.js +3 -3
- package/package.json +5 -2
- package/dist/api/durable-objects/bucket-cache-purge.spec.d.ts +0 -1
- package/dist/api/durable-objects/bucket-cache-purge.spec.js +0 -121
- package/dist/api/durable-objects/queue.spec.d.ts +0 -1
- package/dist/api/durable-objects/queue.spec.js +0 -287
- package/dist/api/durable-objects/sharded-tag-cache.spec.d.ts +0 -1
- package/dist/api/durable-objects/sharded-tag-cache.spec.js +0 -37
- package/dist/api/overrides/queue/memory-queue.spec.d.ts +0 -1
- package/dist/api/overrides/queue/memory-queue.spec.js +0 -76
- package/dist/api/overrides/queue/queue-cache.spec.d.ts +0 -1
- package/dist/api/overrides/queue/queue-cache.spec.js +0 -92
- package/dist/api/overrides/tag-cache/do-sharded-tag-cache.spec.d.ts +0 -1
- package/dist/api/overrides/tag-cache/do-sharded-tag-cache.spec.js +0 -413
- package/dist/api/overrides/tag-cache/tag-cache-filter.spec.d.ts +0 -1
- package/dist/api/overrides/tag-cache/tag-cache-filter.spec.js +0 -97
- package/dist/cli/build/patches/ast/patch-vercel-og-library.spec.d.ts +0 -1
- package/dist/cli/build/patches/ast/patch-vercel-og-library.spec.js +0 -50
- package/dist/cli/build/patches/ast/vercel-og.spec.d.ts +0 -1
- package/dist/cli/build/patches/ast/vercel-og.spec.js +0 -22
- package/dist/cli/build/patches/ast/webpack-runtime.spec.d.ts +0 -1
- package/dist/cli/build/patches/ast/webpack-runtime.spec.js +0 -102
- package/dist/cli/build/patches/index.d.ts +0 -1
- package/dist/cli/build/patches/index.js +0 -1
- package/dist/cli/build/patches/investigated/index.d.ts +0 -2
- package/dist/cli/build/patches/investigated/index.js +0 -2
- package/dist/cli/build/patches/investigated/patch-require.d.ts +0 -4
- package/dist/cli/build/patches/investigated/patch-require.js +0 -6
- package/dist/cli/build/patches/plugins/instrumentation.spec.d.ts +0 -1
- package/dist/cli/build/patches/plugins/instrumentation.spec.js +0 -91
- package/dist/cli/build/patches/plugins/next-server.spec.d.ts +0 -1
- package/dist/cli/build/patches/plugins/next-server.spec.js +0 -429
- package/dist/cli/build/patches/plugins/patch-depd-deprecations.spec.d.ts +0 -1
- package/dist/cli/build/patches/plugins/patch-depd-deprecations.spec.js +0 -29
- package/dist/cli/build/patches/plugins/res-revalidate.spec.d.ts +0 -1
- package/dist/cli/build/patches/plugins/res-revalidate.spec.js +0 -141
- package/dist/cli/build/patches/plugins/use-cache.spec.d.ts +0 -1
- package/dist/cli/build/patches/plugins/use-cache.spec.js +0 -156
- package/dist/cli/build/utils/apply-patches.d.ts +0 -12
- package/dist/cli/build/utils/apply-patches.js +0 -22
- package/dist/cli/build/utils/extract-project-env-vars.spec.d.ts +0 -1
- package/dist/cli/build/utils/extract-project-env-vars.spec.js +0 -67
- package/dist/cli/build/utils/workerd.spec.d.ts +0 -1
- package/dist/cli/build/utils/workerd.spec.js +0 -188
- package/dist/cli/commands/populate-cache.spec.d.ts +0 -1
- package/dist/cli/commands/populate-cache.spec.js +0 -61
- /package/dist/cli/build/{patches/investigated → utils}/copy-package-cli-files.d.ts +0 -0
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import shardedDOTagCache, { AVAILABLE_REGIONS, DOId } from "./do-sharded-tag-cache";
|
|
3
|
-
const hasBeenRevalidatedMock = vi.fn();
|
|
4
|
-
const writeTagsMock = vi.fn();
|
|
5
|
-
const idFromNameMock = vi.fn();
|
|
6
|
-
const getMock = vi
|
|
7
|
-
.fn()
|
|
8
|
-
.mockReturnValue({ hasBeenRevalidated: hasBeenRevalidatedMock, writeTags: writeTagsMock });
|
|
9
|
-
const waitUntilMock = vi.fn().mockImplementation(async (fn) => fn());
|
|
10
|
-
// @ts-expect-error - We define it here only for the test
|
|
11
|
-
globalThis.continent = undefined;
|
|
12
|
-
const sendDLQMock = vi.fn();
|
|
13
|
-
vi.mock("../../cloudflare-context", () => ({
|
|
14
|
-
getCloudflareContext: () => ({
|
|
15
|
-
env: {
|
|
16
|
-
NEXT_TAG_CACHE_DO_SHARDED: { idFromName: idFromNameMock, get: getMock },
|
|
17
|
-
NEXT_TAG_CACHE_DO_SHARDED_DLQ: {
|
|
18
|
-
send: sendDLQMock,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
ctx: { waitUntil: waitUntilMock },
|
|
22
|
-
cf: {
|
|
23
|
-
// @ts-expect-error - We define it here only for the test
|
|
24
|
-
continent: globalThis.continent,
|
|
25
|
-
},
|
|
26
|
-
}),
|
|
27
|
-
}));
|
|
28
|
-
describe("DOShardedTagCache", () => {
|
|
29
|
-
afterEach(() => vi.clearAllMocks());
|
|
30
|
-
describe("generateShardId", () => {
|
|
31
|
-
it("should generate a shardId", () => {
|
|
32
|
-
const cache = shardedDOTagCache();
|
|
33
|
-
const expectedResult = [
|
|
34
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-1" }), tags: ["tag1"] },
|
|
35
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-2" }), tags: ["tag2"] },
|
|
36
|
-
];
|
|
37
|
-
const result = cache.groupTagsByDO({ tags: ["tag1", "tag2"] });
|
|
38
|
-
expect(result).toEqual(expectedResult);
|
|
39
|
-
expect(result[0]?.doId.key).toBe("tag-hard;shard-1;replica-1");
|
|
40
|
-
expect(result[1]?.doId.key).toBe("tag-hard;shard-2;replica-1");
|
|
41
|
-
});
|
|
42
|
-
it("should group tags by shard", () => {
|
|
43
|
-
const cache = shardedDOTagCache();
|
|
44
|
-
const expectedResult = [
|
|
45
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-1" }), tags: ["tag1", "tag6"] },
|
|
46
|
-
];
|
|
47
|
-
const result = cache.groupTagsByDO({ tags: ["tag1", "tag6"] });
|
|
48
|
-
expect(result).toEqual(expectedResult);
|
|
49
|
-
expect(result[0]?.doId.key).toBe("tag-hard;shard-1;replica-1");
|
|
50
|
-
});
|
|
51
|
-
it("should generate the same shardId for the same tag", () => {
|
|
52
|
-
const cache = shardedDOTagCache();
|
|
53
|
-
const firstResult = cache.groupTagsByDO({ tags: ["tag1"] });
|
|
54
|
-
const secondResult = cache.groupTagsByDO({ tags: ["tag1", "tag3", "tag4"] });
|
|
55
|
-
expect(firstResult[0]).toEqual(secondResult[0]);
|
|
56
|
-
});
|
|
57
|
-
it("should split hard and soft tags", () => {
|
|
58
|
-
const cache = shardedDOTagCache();
|
|
59
|
-
const expectedResult = [
|
|
60
|
-
{ doId: expect.objectContaining({ shardId: "tag-soft;shard-3" }), tags: ["_N_T_/tag1"] },
|
|
61
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-1", replicaId: 1 }), tags: ["tag1"] },
|
|
62
|
-
];
|
|
63
|
-
const result = cache.groupTagsByDO({ tags: ["tag1", "_N_T_/tag1"] });
|
|
64
|
-
expect(result).toEqual(expectedResult);
|
|
65
|
-
expect(result[1]?.doId.key).toBe("tag-hard;shard-1;replica-1");
|
|
66
|
-
expect(result[0]?.doId.key).toBe("tag-soft;shard-3;replica-1");
|
|
67
|
-
});
|
|
68
|
-
describe("with shard replication", () => {
|
|
69
|
-
it("should generate all doIds if generateAllReplicas is true", () => {
|
|
70
|
-
const cache = shardedDOTagCache({
|
|
71
|
-
baseShardSize: 4,
|
|
72
|
-
shardReplication: { numberOfSoftReplicas: 4, numberOfHardReplicas: 2 },
|
|
73
|
-
});
|
|
74
|
-
const expectedResult = [
|
|
75
|
-
{ doId: expect.objectContaining({ shardId: "tag-soft;shard-3" }), tags: ["_N_T_/tag1"] },
|
|
76
|
-
{ doId: expect.objectContaining({ shardId: "tag-soft;shard-3" }), tags: ["_N_T_/tag1"] },
|
|
77
|
-
{ doId: expect.objectContaining({ shardId: "tag-soft;shard-3" }), tags: ["_N_T_/tag1"] },
|
|
78
|
-
{ doId: expect.objectContaining({ shardId: "tag-soft;shard-3" }), tags: ["_N_T_/tag1"] },
|
|
79
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-1" }), tags: ["tag1"] },
|
|
80
|
-
{ doId: expect.objectContaining({ shardId: "tag-hard;shard-1" }), tags: ["tag1"] },
|
|
81
|
-
];
|
|
82
|
-
const result = cache.groupTagsByDO({ tags: ["tag1", "_N_T_/tag1"], generateAllReplicas: true });
|
|
83
|
-
expect(result).toEqual(expectedResult);
|
|
84
|
-
});
|
|
85
|
-
it("should generate only one doIds by tag type if generateAllReplicas is false", () => {
|
|
86
|
-
const cache = shardedDOTagCache({
|
|
87
|
-
baseShardSize: 4,
|
|
88
|
-
shardReplication: { numberOfSoftReplicas: 4, numberOfHardReplicas: 2 },
|
|
89
|
-
});
|
|
90
|
-
const shardedTagCollection = cache.groupTagsByDO({
|
|
91
|
-
tags: ["tag1", "_N_T_/tag1"],
|
|
92
|
-
generateAllReplicas: false,
|
|
93
|
-
});
|
|
94
|
-
expect(shardedTagCollection.length).toBe(2);
|
|
95
|
-
const firstDOId = shardedTagCollection[0]?.doId;
|
|
96
|
-
const secondDOId = shardedTagCollection[1]?.doId;
|
|
97
|
-
expect(firstDOId?.shardId).toBe("tag-soft;shard-3");
|
|
98
|
-
expect(secondDOId?.shardId).toBe("tag-hard;shard-1");
|
|
99
|
-
// We still need to check if the last part is between the correct boundaries
|
|
100
|
-
expect(firstDOId?.replicaId).toBeGreaterThanOrEqual(1);
|
|
101
|
-
expect(firstDOId?.replicaId).toBeLessThanOrEqual(4);
|
|
102
|
-
expect(secondDOId?.replicaId).toBeGreaterThanOrEqual(1);
|
|
103
|
-
expect(secondDOId?.replicaId).toBeLessThanOrEqual(2);
|
|
104
|
-
});
|
|
105
|
-
it("should generate one doIds, but in the default region", () => {
|
|
106
|
-
const cache = shardedDOTagCache({
|
|
107
|
-
baseShardSize: 4,
|
|
108
|
-
shardReplication: {
|
|
109
|
-
numberOfSoftReplicas: 2,
|
|
110
|
-
numberOfHardReplicas: 2,
|
|
111
|
-
regionalReplication: {
|
|
112
|
-
defaultRegion: "enam",
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
const shardedTagCollection = cache.groupTagsByDO({
|
|
117
|
-
tags: ["tag1", "_N_T_/tag1"],
|
|
118
|
-
generateAllReplicas: false,
|
|
119
|
-
});
|
|
120
|
-
expect(shardedTagCollection.length).toBe(2);
|
|
121
|
-
const firstDOId = shardedTagCollection[0]?.doId;
|
|
122
|
-
const secondDOId = shardedTagCollection[1]?.doId;
|
|
123
|
-
expect(firstDOId?.shardId).toBe("tag-soft;shard-3");
|
|
124
|
-
expect(firstDOId?.region).toBe("enam");
|
|
125
|
-
expect(secondDOId?.shardId).toBe("tag-hard;shard-1");
|
|
126
|
-
expect(secondDOId?.region).toBe("enam");
|
|
127
|
-
// We still need to check if the last part is between the correct boundaries
|
|
128
|
-
expect(firstDOId?.replicaId).toBeGreaterThanOrEqual(1);
|
|
129
|
-
expect(firstDOId?.replicaId).toBeLessThanOrEqual(2);
|
|
130
|
-
expect(secondDOId?.replicaId).toBeGreaterThanOrEqual(1);
|
|
131
|
-
expect(secondDOId?.replicaId).toBeLessThanOrEqual(2);
|
|
132
|
-
});
|
|
133
|
-
it("should generate one doIds, but in the correct region", () => {
|
|
134
|
-
// @ts-expect-error - We define it here only for the test
|
|
135
|
-
globalThis.continent = "EU";
|
|
136
|
-
const cache = shardedDOTagCache({
|
|
137
|
-
baseShardSize: 4,
|
|
138
|
-
shardReplication: {
|
|
139
|
-
numberOfSoftReplicas: 2,
|
|
140
|
-
numberOfHardReplicas: 2,
|
|
141
|
-
regionalReplication: {
|
|
142
|
-
defaultRegion: "enam",
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
const shardedTagCollection = cache.groupTagsByDO({
|
|
147
|
-
tags: ["tag1", "_N_T_/tag1"],
|
|
148
|
-
generateAllReplicas: false,
|
|
149
|
-
});
|
|
150
|
-
expect(shardedTagCollection.length).toBe(2);
|
|
151
|
-
expect(shardedTagCollection[0]?.doId.region).toBe("weur");
|
|
152
|
-
expect(shardedTagCollection[1]?.doId.region).toBe("weur");
|
|
153
|
-
//@ts-expect-error - We need to reset the global variable
|
|
154
|
-
globalThis.continent = undefined;
|
|
155
|
-
});
|
|
156
|
-
it("should generate all the appropriate replicas in all the regions with enableRegionalReplication", () => {
|
|
157
|
-
const cache = shardedDOTagCache({
|
|
158
|
-
baseShardSize: 4,
|
|
159
|
-
shardReplication: {
|
|
160
|
-
numberOfSoftReplicas: 2,
|
|
161
|
-
numberOfHardReplicas: 2,
|
|
162
|
-
regionalReplication: {
|
|
163
|
-
defaultRegion: "enam",
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
const shardedTagCollection = cache.groupTagsByDO({
|
|
168
|
-
tags: ["tag1", "_N_T_/tag1"],
|
|
169
|
-
generateAllReplicas: true,
|
|
170
|
-
});
|
|
171
|
-
// 6 regions times 4 shards replica
|
|
172
|
-
expect(shardedTagCollection.length).toBe(24);
|
|
173
|
-
shardedTagCollection.forEach(({ doId }) => {
|
|
174
|
-
expect(AVAILABLE_REGIONS).toContain(doId.region);
|
|
175
|
-
// It should end with the region
|
|
176
|
-
expect(doId.key).toMatch(/tag-(soft|hard);shard-\d;replica-\d;region-(enam|weur|sam|afr|apac|oc)$/);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
describe("hasBeenRevalidated", () => {
|
|
182
|
-
beforeEach(() => {
|
|
183
|
-
globalThis.openNextConfig = {
|
|
184
|
-
dangerous: { disableTagCache: false },
|
|
185
|
-
};
|
|
186
|
-
});
|
|
187
|
-
it("should return false if the cache is disabled", async () => {
|
|
188
|
-
globalThis.openNextConfig = {
|
|
189
|
-
dangerous: { disableTagCache: true },
|
|
190
|
-
};
|
|
191
|
-
const cache = shardedDOTagCache();
|
|
192
|
-
const result = await cache.hasBeenRevalidated(["tag1"]);
|
|
193
|
-
expect(result).toBe(false);
|
|
194
|
-
expect(idFromNameMock).not.toHaveBeenCalled();
|
|
195
|
-
});
|
|
196
|
-
it("should return false if stub return false", async () => {
|
|
197
|
-
const cache = shardedDOTagCache();
|
|
198
|
-
cache.getFromRegionalCache = vi.fn();
|
|
199
|
-
hasBeenRevalidatedMock.mockImplementationOnce(() => false);
|
|
200
|
-
const result = await cache.hasBeenRevalidated(["tag1"], 123456);
|
|
201
|
-
expect(cache.getFromRegionalCache).toHaveBeenCalled();
|
|
202
|
-
expect(idFromNameMock).toHaveBeenCalled();
|
|
203
|
-
expect(hasBeenRevalidatedMock).toHaveBeenCalled();
|
|
204
|
-
expect(result).toBe(false);
|
|
205
|
-
});
|
|
206
|
-
it("should return true if stub return true", async () => {
|
|
207
|
-
const cache = shardedDOTagCache();
|
|
208
|
-
cache.getFromRegionalCache = vi.fn();
|
|
209
|
-
hasBeenRevalidatedMock.mockImplementationOnce(() => true);
|
|
210
|
-
const result = await cache.hasBeenRevalidated(["tag1"], 123456);
|
|
211
|
-
expect(cache.getFromRegionalCache).toHaveBeenCalled();
|
|
212
|
-
expect(idFromNameMock).toHaveBeenCalled();
|
|
213
|
-
expect(hasBeenRevalidatedMock).toHaveBeenCalledWith(["tag1"], 123456);
|
|
214
|
-
expect(result).toBe(true);
|
|
215
|
-
});
|
|
216
|
-
it("should return false if it throws", async () => {
|
|
217
|
-
const cache = shardedDOTagCache();
|
|
218
|
-
cache.getFromRegionalCache = vi.fn();
|
|
219
|
-
hasBeenRevalidatedMock.mockImplementationOnce(() => {
|
|
220
|
-
throw new Error("error");
|
|
221
|
-
});
|
|
222
|
-
const result = await cache.hasBeenRevalidated(["tag1"], 123456);
|
|
223
|
-
expect(cache.getFromRegionalCache).toHaveBeenCalled();
|
|
224
|
-
expect(idFromNameMock).toHaveBeenCalled();
|
|
225
|
-
expect(hasBeenRevalidatedMock).toHaveBeenCalled();
|
|
226
|
-
expect(result).toBe(false);
|
|
227
|
-
});
|
|
228
|
-
it("Should return from the cache if it was found there", async () => {
|
|
229
|
-
const cache = shardedDOTagCache();
|
|
230
|
-
cache.getFromRegionalCache = vi.fn().mockReturnValueOnce(new Response("true"));
|
|
231
|
-
const result = await cache.hasBeenRevalidated(["tag1"], 123456);
|
|
232
|
-
expect(result).toBe(true);
|
|
233
|
-
expect(idFromNameMock).not.toHaveBeenCalled();
|
|
234
|
-
expect(hasBeenRevalidatedMock).not.toHaveBeenCalled();
|
|
235
|
-
});
|
|
236
|
-
it("should try to put the result in the cache if it was not revalidated", async () => {
|
|
237
|
-
const cache = shardedDOTagCache();
|
|
238
|
-
cache.getFromRegionalCache = vi.fn();
|
|
239
|
-
cache.putToRegionalCache = vi.fn();
|
|
240
|
-
hasBeenRevalidatedMock.mockImplementationOnce(() => false);
|
|
241
|
-
const result = await cache.hasBeenRevalidated(["tag1"], 123456);
|
|
242
|
-
expect(result).toBe(false);
|
|
243
|
-
expect(waitUntilMock).toHaveBeenCalled();
|
|
244
|
-
expect(cache.putToRegionalCache).toHaveBeenCalled();
|
|
245
|
-
});
|
|
246
|
-
it("should call all the durable object instance", async () => {
|
|
247
|
-
const cache = shardedDOTagCache();
|
|
248
|
-
cache.getFromRegionalCache = vi.fn();
|
|
249
|
-
const result = await cache.hasBeenRevalidated(["tag1", "tag2"], 123456);
|
|
250
|
-
expect(result).toBe(false);
|
|
251
|
-
expect(idFromNameMock).toHaveBeenCalledTimes(2);
|
|
252
|
-
expect(hasBeenRevalidatedMock).toHaveBeenCalledTimes(2);
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
describe("writeTags", () => {
|
|
256
|
-
beforeEach(() => {
|
|
257
|
-
globalThis.openNextConfig = {
|
|
258
|
-
dangerous: { disableTagCache: false },
|
|
259
|
-
};
|
|
260
|
-
vi.useFakeTimers();
|
|
261
|
-
vi.setSystemTime(1000);
|
|
262
|
-
});
|
|
263
|
-
afterEach(() => {
|
|
264
|
-
vi.useRealTimers();
|
|
265
|
-
});
|
|
266
|
-
it("should return early if the cache is disabled", async () => {
|
|
267
|
-
globalThis.openNextConfig = {
|
|
268
|
-
dangerous: { disableTagCache: true },
|
|
269
|
-
};
|
|
270
|
-
const cache = shardedDOTagCache();
|
|
271
|
-
await cache.writeTags(["tag1"]);
|
|
272
|
-
expect(idFromNameMock).not.toHaveBeenCalled();
|
|
273
|
-
expect(writeTagsMock).not.toHaveBeenCalled();
|
|
274
|
-
});
|
|
275
|
-
it("should write the tags to the cache", async () => {
|
|
276
|
-
const cache = shardedDOTagCache();
|
|
277
|
-
await cache.writeTags(["tag1"]);
|
|
278
|
-
expect(idFromNameMock).toHaveBeenCalled();
|
|
279
|
-
expect(writeTagsMock).toHaveBeenCalled();
|
|
280
|
-
expect(writeTagsMock).toHaveBeenCalledWith(["tag1"], 1000);
|
|
281
|
-
});
|
|
282
|
-
it("should write the tags to the cache for multiple shards", async () => {
|
|
283
|
-
const cache = shardedDOTagCache();
|
|
284
|
-
await cache.writeTags(["tag1", "tag2"]);
|
|
285
|
-
expect(idFromNameMock).toHaveBeenCalledTimes(2);
|
|
286
|
-
expect(writeTagsMock).toHaveBeenCalledTimes(2);
|
|
287
|
-
expect(writeTagsMock).toHaveBeenCalledWith(["tag1"], 1000);
|
|
288
|
-
expect(writeTagsMock).toHaveBeenCalledWith(["tag2"], 1000);
|
|
289
|
-
});
|
|
290
|
-
it('should write to all the replicated shards if "generateAllReplicas" is true', async () => {
|
|
291
|
-
const cache = shardedDOTagCache({
|
|
292
|
-
baseShardSize: 4,
|
|
293
|
-
shardReplication: { numberOfSoftReplicas: 4, numberOfHardReplicas: 2 },
|
|
294
|
-
});
|
|
295
|
-
await cache.writeTags(["tag1", "_N_T_/tag1"]);
|
|
296
|
-
expect(idFromNameMock).toHaveBeenCalledTimes(6);
|
|
297
|
-
expect(writeTagsMock).toHaveBeenCalledTimes(6);
|
|
298
|
-
expect(writeTagsMock).toHaveBeenCalledWith(["tag1"], 1000);
|
|
299
|
-
expect(writeTagsMock).toHaveBeenCalledWith(["_N_T_/tag1"], 1000);
|
|
300
|
-
});
|
|
301
|
-
it("should call deleteRegionalCache", async () => {
|
|
302
|
-
const cache = shardedDOTagCache();
|
|
303
|
-
cache.deleteRegionalCache = vi.fn();
|
|
304
|
-
await cache.writeTags(["tag1"]);
|
|
305
|
-
expect(cache.deleteRegionalCache).toHaveBeenCalled();
|
|
306
|
-
expect(cache.deleteRegionalCache).toHaveBeenCalledWith({
|
|
307
|
-
doId: expect.objectContaining({ key: "tag-hard;shard-1;replica-1" }),
|
|
308
|
-
tags: ["tag1"],
|
|
309
|
-
type: "boolean",
|
|
310
|
-
});
|
|
311
|
-
// expect(cache.deleteRegionalCache).toHaveBeenCalledWith("tag-hard;shard-1;replica-1", ["tag1"]);
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
describe("getCacheInstance", () => {
|
|
315
|
-
it("should return undefined by default", async () => {
|
|
316
|
-
const cache = shardedDOTagCache();
|
|
317
|
-
expect(await cache.getCacheInstance()).toBeUndefined();
|
|
318
|
-
});
|
|
319
|
-
it("should try to return the cache instance if regional cache is enabled", async () => {
|
|
320
|
-
// @ts-expect-error - Defined on cloudfare context
|
|
321
|
-
globalThis.caches = {
|
|
322
|
-
open: vi.fn().mockResolvedValue("cache"),
|
|
323
|
-
};
|
|
324
|
-
const cache = shardedDOTagCache({ baseShardSize: 4, regionalCache: true });
|
|
325
|
-
expect(cache.localCache).toBeUndefined();
|
|
326
|
-
expect(await cache.getCacheInstance()).toBe("cache");
|
|
327
|
-
expect(cache.localCache).toBe("cache");
|
|
328
|
-
// @ts-expect-error - Defined on cloudfare context
|
|
329
|
-
globalThis.caches = undefined;
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
describe("getFromRegionalCache", () => {
|
|
333
|
-
it("should return undefined if regional cache is disabled", async () => {
|
|
334
|
-
const cache = shardedDOTagCache();
|
|
335
|
-
const doId = new DOId({
|
|
336
|
-
baseShardId: "shard-1",
|
|
337
|
-
numberOfReplicas: 1,
|
|
338
|
-
shardType: "hard",
|
|
339
|
-
});
|
|
340
|
-
expect(await cache.getFromRegionalCache({ doId, tags: ["tag1"], type: "boolean" })).toBeUndefined();
|
|
341
|
-
});
|
|
342
|
-
it("should call .match on the cache", async () => {
|
|
343
|
-
// @ts-expect-error - Defined on cloudfare context
|
|
344
|
-
globalThis.caches = {
|
|
345
|
-
open: vi.fn().mockResolvedValue({
|
|
346
|
-
match: vi.fn().mockResolvedValue("response"),
|
|
347
|
-
}),
|
|
348
|
-
};
|
|
349
|
-
const cache = shardedDOTagCache({ baseShardSize: 4, regionalCache: true });
|
|
350
|
-
const doId = new DOId({
|
|
351
|
-
baseShardId: "shard-1",
|
|
352
|
-
numberOfReplicas: 1,
|
|
353
|
-
shardType: "hard",
|
|
354
|
-
});
|
|
355
|
-
expect(await cache.getFromRegionalCache({ doId, tags: ["tag1"], type: "boolean" })).toBe("response");
|
|
356
|
-
// @ts-expect-error - Defined on cloudfare context
|
|
357
|
-
globalThis.caches = undefined;
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
describe("getCacheKey", () => {
|
|
361
|
-
it("should return the cache key without the random part", async () => {
|
|
362
|
-
const cache = shardedDOTagCache();
|
|
363
|
-
const doId1 = new DOId({ baseShardId: "shard-0", numberOfReplicas: 1, shardType: "hard" });
|
|
364
|
-
expect(cache.getCacheUrlKey({ doId: doId1, tags: ["_N_T_/tag1"], type: "boolean" })).toBe("http://local.cache/shard/tag-hard;shard-0?type=boolean&tags=_N_T_%2Ftag1");
|
|
365
|
-
const doId2 = new DOId({
|
|
366
|
-
baseShardId: "shard-1",
|
|
367
|
-
numberOfReplicas: 1,
|
|
368
|
-
shardType: "hard",
|
|
369
|
-
});
|
|
370
|
-
expect(cache.getCacheUrlKey({ doId: doId2, tags: ["tag1"], type: "boolean" })).toBe("http://local.cache/shard/tag-hard;shard-1?type=boolean&tags=tag1");
|
|
371
|
-
});
|
|
372
|
-
});
|
|
373
|
-
describe("performWriteTagsWithRetry", () => {
|
|
374
|
-
it("should retry if it fails", async () => {
|
|
375
|
-
vi.useFakeTimers();
|
|
376
|
-
vi.setSystemTime(1000);
|
|
377
|
-
const cache = shardedDOTagCache();
|
|
378
|
-
writeTagsMock.mockImplementationOnce(() => {
|
|
379
|
-
throw new Error("error");
|
|
380
|
-
});
|
|
381
|
-
const spiedFn = vi.spyOn(cache, "performWriteTagsWithRetry");
|
|
382
|
-
const doId = new DOId({
|
|
383
|
-
baseShardId: "shard-1",
|
|
384
|
-
numberOfReplicas: 1,
|
|
385
|
-
shardType: "hard",
|
|
386
|
-
});
|
|
387
|
-
await cache.performWriteTagsWithRetry(doId, ["tag1"], Date.now());
|
|
388
|
-
expect(writeTagsMock).toHaveBeenCalledTimes(2);
|
|
389
|
-
expect(spiedFn).toHaveBeenCalledTimes(2);
|
|
390
|
-
expect(spiedFn).toHaveBeenCalledWith(doId, ["tag1"], 1000, 1);
|
|
391
|
-
expect(sendDLQMock).not.toHaveBeenCalled();
|
|
392
|
-
vi.useRealTimers();
|
|
393
|
-
});
|
|
394
|
-
it("should stop retrying after 3 times", async () => {
|
|
395
|
-
vi.useFakeTimers();
|
|
396
|
-
vi.setSystemTime(1000);
|
|
397
|
-
const cache = shardedDOTagCache();
|
|
398
|
-
writeTagsMock.mockImplementationOnce(() => {
|
|
399
|
-
throw new Error("error");
|
|
400
|
-
});
|
|
401
|
-
const spiedFn = vi.spyOn(cache, "performWriteTagsWithRetry");
|
|
402
|
-
await cache.performWriteTagsWithRetry(new DOId({ baseShardId: "shard-1", numberOfReplicas: 1, shardType: "hard" }), ["tag1"], Date.now(), 3);
|
|
403
|
-
expect(writeTagsMock).toHaveBeenCalledTimes(1);
|
|
404
|
-
expect(spiedFn).toHaveBeenCalledTimes(1);
|
|
405
|
-
expect(sendDLQMock).toHaveBeenCalledWith({
|
|
406
|
-
failingShardId: "tag-hard;shard-1;replica-1",
|
|
407
|
-
failingTags: ["tag1"],
|
|
408
|
-
lastModified: 1000,
|
|
409
|
-
});
|
|
410
|
-
vi.useRealTimers();
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { softTagFilter, withFilter } from "./tag-cache-filter";
|
|
3
|
-
const mockedTagCache = {
|
|
4
|
-
name: "mocked",
|
|
5
|
-
mode: "nextMode",
|
|
6
|
-
getLastRevalidated: vi.fn(),
|
|
7
|
-
getPathsByTags: vi.fn(),
|
|
8
|
-
hasBeenRevalidated: vi.fn(),
|
|
9
|
-
writeTags: vi.fn(),
|
|
10
|
-
};
|
|
11
|
-
const filterFn = (tag) => tag.startsWith("valid_");
|
|
12
|
-
describe("withFilter", () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
it("should filter out tags based on writeTags", async () => {
|
|
17
|
-
const tagCache = withFilter({
|
|
18
|
-
tagCache: mockedTagCache,
|
|
19
|
-
filterFn,
|
|
20
|
-
});
|
|
21
|
-
const tags = ["valid_tag", "invalid_tag"];
|
|
22
|
-
await tagCache.writeTags(tags);
|
|
23
|
-
expect(mockedTagCache.writeTags).toHaveBeenCalledWith(["valid_tag"]);
|
|
24
|
-
});
|
|
25
|
-
it("should not call writeTags if no tags are valid", async () => {
|
|
26
|
-
const tagCache = withFilter({
|
|
27
|
-
tagCache: mockedTagCache,
|
|
28
|
-
filterFn,
|
|
29
|
-
});
|
|
30
|
-
const tags = ["invalid_tag"];
|
|
31
|
-
await tagCache.writeTags(tags);
|
|
32
|
-
expect(mockedTagCache.writeTags).not.toHaveBeenCalled();
|
|
33
|
-
});
|
|
34
|
-
it("should filter out tags based on hasBeenRevalidated", async () => {
|
|
35
|
-
const tagCache = withFilter({
|
|
36
|
-
tagCache: mockedTagCache,
|
|
37
|
-
filterFn,
|
|
38
|
-
});
|
|
39
|
-
const tags = ["valid_tag", "invalid_tag"];
|
|
40
|
-
const lastModified = Date.now();
|
|
41
|
-
await tagCache.hasBeenRevalidated(tags, lastModified);
|
|
42
|
-
expect(mockedTagCache.hasBeenRevalidated).toHaveBeenCalledWith(["valid_tag"], lastModified);
|
|
43
|
-
});
|
|
44
|
-
it("should not call hasBeenRevalidated if no tags are valid", async () => {
|
|
45
|
-
const tagCache = withFilter({
|
|
46
|
-
tagCache: mockedTagCache,
|
|
47
|
-
filterFn,
|
|
48
|
-
});
|
|
49
|
-
const tags = ["invalid_tag"];
|
|
50
|
-
const lastModified = Date.now();
|
|
51
|
-
await tagCache.hasBeenRevalidated(tags, lastModified);
|
|
52
|
-
expect(mockedTagCache.hasBeenRevalidated).not.toHaveBeenCalled();
|
|
53
|
-
});
|
|
54
|
-
it("should filter out tags based on getPathsByTags", async () => {
|
|
55
|
-
const tagCache = withFilter({
|
|
56
|
-
tagCache: mockedTagCache,
|
|
57
|
-
filterFn,
|
|
58
|
-
});
|
|
59
|
-
const tags = ["valid_tag", "invalid_tag"];
|
|
60
|
-
await tagCache.getPathsByTags?.(tags);
|
|
61
|
-
expect(mockedTagCache.getPathsByTags).toHaveBeenCalledWith(["valid_tag"]);
|
|
62
|
-
});
|
|
63
|
-
it("should not call getPathsByTags if no tags are valid", async () => {
|
|
64
|
-
const tagCache = withFilter({
|
|
65
|
-
tagCache: mockedTagCache,
|
|
66
|
-
filterFn,
|
|
67
|
-
});
|
|
68
|
-
const tags = ["invalid_tag"];
|
|
69
|
-
await tagCache.getPathsByTags?.(tags);
|
|
70
|
-
expect(mockedTagCache.getPathsByTags).not.toHaveBeenCalled();
|
|
71
|
-
});
|
|
72
|
-
it("should return the correct name", () => {
|
|
73
|
-
const tagCache = withFilter({
|
|
74
|
-
tagCache: mockedTagCache,
|
|
75
|
-
filterFn,
|
|
76
|
-
});
|
|
77
|
-
expect(tagCache.name).toBe("filtered-mocked");
|
|
78
|
-
});
|
|
79
|
-
it("should not create a function if getPathsByTags is not defined", async () => {
|
|
80
|
-
const tagCache = withFilter({
|
|
81
|
-
tagCache: {
|
|
82
|
-
...mockedTagCache,
|
|
83
|
-
getPathsByTags: undefined,
|
|
84
|
-
},
|
|
85
|
-
filterFn,
|
|
86
|
-
});
|
|
87
|
-
expect(tagCache.getPathsByTags).toBeUndefined();
|
|
88
|
-
});
|
|
89
|
-
it("should filter soft tags", () => {
|
|
90
|
-
const tagCache = withFilter({
|
|
91
|
-
tagCache: mockedTagCache,
|
|
92
|
-
filterFn: softTagFilter,
|
|
93
|
-
});
|
|
94
|
-
tagCache.writeTags(["valid_tag", "_N_T_/", "_N_T_/test", "_N_T_/layout"]);
|
|
95
|
-
expect(mockedTagCache.writeTags).toHaveBeenCalledWith(["valid_tag"]);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import mockFs from "mock-fs";
|
|
4
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
5
|
-
import { patchVercelOgLibrary } from "./patch-vercel-og-library";
|
|
6
|
-
const nodeModulesVercelOgDir = "node_modules/.pnpm/next@14.2.11/node_modules/next/dist/compiled/@vercel/og";
|
|
7
|
-
const nextServerOgNftPath = "examples/api/.next/server/app/og/route.js.nft.json";
|
|
8
|
-
const openNextFunctionDir = "examples/api/.open-next/server-functions/default/examples/api";
|
|
9
|
-
const openNextOgRoutePath = path.join(openNextFunctionDir, ".next/server/app/og/route.js");
|
|
10
|
-
const openNextVercelOgDir = path.join(openNextFunctionDir, "node_modules/next/dist/compiled/@vercel/og");
|
|
11
|
-
const buildOpts = {
|
|
12
|
-
appBuildOutputPath: "examples/api",
|
|
13
|
-
monorepoRoot: "",
|
|
14
|
-
outputDir: "examples/api/.open-next",
|
|
15
|
-
};
|
|
16
|
-
describe("patchVercelOgLibrary", () => {
|
|
17
|
-
beforeAll(() => {
|
|
18
|
-
mockFs();
|
|
19
|
-
mkdirSync(nodeModulesVercelOgDir, { recursive: true });
|
|
20
|
-
mkdirSync(path.dirname(nextServerOgNftPath), { recursive: true });
|
|
21
|
-
mkdirSync(path.dirname(openNextOgRoutePath), { recursive: true });
|
|
22
|
-
mkdirSync(openNextVercelOgDir, { recursive: true });
|
|
23
|
-
writeFileSync(nextServerOgNftPath, JSON.stringify({ version: 1, files: [`../../../../../../${nodeModulesVercelOgDir}/index.node.js`] }));
|
|
24
|
-
writeFileSync(path.join(nodeModulesVercelOgDir, "index.edge.js"), `var fallbackFont = fetch(new URL("./noto-sans-v27-latin-regular.ttf", import.meta.url)).then((res) => res.arrayBuffer());`);
|
|
25
|
-
writeFileSync(openNextOgRoutePath, `e.exports=import("next/dist/compiled/@vercel/og/index.node.js")`);
|
|
26
|
-
writeFileSync(path.join(openNextVercelOgDir, "index.node.js"), "");
|
|
27
|
-
writeFileSync(path.join(openNextVercelOgDir, "noto-sans-v27-latin-regular.ttf"), "");
|
|
28
|
-
});
|
|
29
|
-
afterAll(() => mockFs.restore());
|
|
30
|
-
it("should patch the open-next files correctly", () => {
|
|
31
|
-
patchVercelOgLibrary(buildOpts);
|
|
32
|
-
expect(readdirSync(openNextVercelOgDir)).toMatchInlineSnapshot(`
|
|
33
|
-
[
|
|
34
|
-
"index.edge.js",
|
|
35
|
-
"index.node.js",
|
|
36
|
-
"noto-sans-v27-latin-regular.ttf.bin",
|
|
37
|
-
]
|
|
38
|
-
`);
|
|
39
|
-
expect(readFileSync(path.join(openNextVercelOgDir, "index.edge.js"), { encoding: "utf-8" }))
|
|
40
|
-
.toMatchInlineSnapshot(`
|
|
41
|
-
"async function getFallbackFont() {
|
|
42
|
-
// .bin is used so that a loader does not need to be configured for .ttf files
|
|
43
|
-
return (await import("./noto-sans-v27-latin-regular.ttf.bin")).default;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
var fallbackFont = getFallbackFont();"
|
|
47
|
-
`);
|
|
48
|
-
expect(readFileSync(openNextOgRoutePath, { encoding: "utf-8" })).toMatchInlineSnapshot(`"e.exports=import("next/dist/compiled/@vercel/og/index.edge.js")"`);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { patchCode } from "@opennextjs/aws/build/patch/astCodePatcher.js";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { vercelOgFallbackFontRule, vercelOgImportRule } from "./vercel-og";
|
|
4
|
-
describe("vercelOgImportRule", () => {
|
|
5
|
-
it("should rewrite a node import to an edge import", () => {
|
|
6
|
-
const code = `e.exports=import("next/dist/compiled/@vercel/og/index.node.js")`;
|
|
7
|
-
expect(patchCode(code, vercelOgImportRule)).toMatchInlineSnapshot(`"e.exports=import("next/dist/compiled/@vercel/og/index.edge.js")"`);
|
|
8
|
-
});
|
|
9
|
-
});
|
|
10
|
-
describe("vercelOgFallbackFontRule", () => {
|
|
11
|
-
it("should replace a fetch call for a font with an import", () => {
|
|
12
|
-
const code = `var fallbackFont = fetch(new URL("./noto-sans-v27-latin-regular.ttf", import.meta.url)).then((res) => res.arrayBuffer());`;
|
|
13
|
-
expect(patchCode(code, vercelOgFallbackFontRule)).toMatchInlineSnapshot(`
|
|
14
|
-
"async function getFallbackFont() {
|
|
15
|
-
// .bin is used so that a loader does not need to be configured for .ttf files
|
|
16
|
-
return (await import("./noto-sans-v27-latin-regular.ttf.bin")).default;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
var fallbackFont = getFallbackFont();"
|
|
20
|
-
`);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|