@bigcommerce/catalyst 1.2.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/README.md +1 -1
- package/dist/cli.js +513 -193
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/open-next.config.ts +59 -5
package/package.json
CHANGED
|
@@ -1,17 +1,72 @@
|
|
|
1
1
|
import { defineCloudflareConfig, type OpenNextConfig } from '@opennextjs/cloudflare';
|
|
2
|
-
import { purgeCache } from '@opennextjs/cloudflare/overrides/cache-purge/index';
|
|
3
2
|
import r2IncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache';
|
|
4
3
|
import { withRegionalCache } from '@opennextjs/cloudflare/overrides/incremental-cache/regional-cache';
|
|
5
|
-
import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue';
|
|
6
4
|
import queueCache from '@opennextjs/cloudflare/overrides/queue/queue-cache';
|
|
7
5
|
import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache';
|
|
8
6
|
|
|
7
|
+
// OpenNext's `doQueue` cannot be used on native hosting: its Durable Object
|
|
8
|
+
// requires a `WORKER_SELF_REFERENCE` service binding, which a dispatch-namespace
|
|
9
|
+
// script cannot have. See LTRAC-1457 for why the alternatives were rejected.
|
|
10
|
+
//
|
|
11
|
+
// No binding is required. The revalidation is a HEAD request to the page's own
|
|
12
|
+
// public URL carrying the build-time preview secret, which is exactly what the
|
|
13
|
+
// Durable Object issues once it holds the service handle. Sending it with a
|
|
14
|
+
// plain `fetch` leaves and re-enters through the dispatch router and arrives at
|
|
15
|
+
// the same Worker. `global_fetch_strictly_public` is set, so the subrequest is
|
|
16
|
+
// not short-circuited internally.
|
|
17
|
+
//
|
|
18
|
+
// Wrapped in `queueCache` below so concurrent stale hits for one path collapse
|
|
19
|
+
// into a single revalidation. What is lost relative to the Durable Object is its
|
|
20
|
+
// retry and max-concurrency handling; a failed revalidation is retried on the
|
|
21
|
+
// next stale hit rather than by the queue itself.
|
|
22
|
+
|
|
23
|
+
// Matches the Durable Object's default. Without a bound, a hanging revalidation
|
|
24
|
+
// would sit in `waitUntil` holding the invocation alive.
|
|
25
|
+
const REVALIDATION_TIMEOUT_MS = 10_000;
|
|
26
|
+
|
|
27
|
+
const selfFetchQueue = {
|
|
28
|
+
name: 'self-fetch-queue',
|
|
29
|
+
async send({ MessageBody: { host, url } }: { MessageBody: { host: string; url: string } }) {
|
|
30
|
+
const protocol = host.includes('localhost') ? 'http' : 'https';
|
|
31
|
+
|
|
32
|
+
const response = await fetch(`${protocol}://${host}${url}`, {
|
|
33
|
+
method: 'HEAD',
|
|
34
|
+
headers: {
|
|
35
|
+
// Inlined at build time; authorizes the revalidation. The name is
|
|
36
|
+
// Next's, so the leading underscores are not ours to rename.
|
|
37
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
38
|
+
'x-prerender-revalidate': process.env.__NEXT_PREVIEW_MODE_ID ?? '',
|
|
39
|
+
'x-isr': '1',
|
|
40
|
+
},
|
|
41
|
+
signal: AbortSignal.timeout(REVALIDATION_TIMEOUT_MS),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// `fetch` resolves for 4xx/5xx, so a failed regeneration would otherwise be
|
|
45
|
+
// indistinguishable from success. Throwing surfaces it: `queueCache` logs
|
|
46
|
+
// the error and, with `waitForQueueAck`, skips caching the attempt — so the
|
|
47
|
+
// next stale hit retries rather than the failure being swallowed. Silent
|
|
48
|
+
// failure is the exact bug this queue exists to fix.
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error(`Revalidation of ${url} failed with status ${response.status}`);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
9
55
|
const cloudflareConfig = defineCloudflareConfig({
|
|
56
|
+
// The absence of `cachePurge` and `bypassTagCacheOnCacheHit` is deliberate.
|
|
57
|
+
// Invalidating regional (Cache API) entries needs either a CDN purge that
|
|
58
|
+
// evicts them or a tag-cache check on every hit; this takes the second.
|
|
59
|
+
//
|
|
60
|
+
// Do not restore `cachePurge` without reading LTRAC-1458 first. OpenNext's
|
|
61
|
+
// `isPurgeCacheEnabled()` checks only whether it is *declared*, never whether
|
|
62
|
+
// it can authenticate, and declaring it turns off both
|
|
63
|
+
// `shouldLazilyUpdateOnCacheHit` and the tag check. A purge that cannot
|
|
64
|
+
// authenticate therefore leaves entries neither purged, nor refreshed from R2,
|
|
65
|
+
// nor tag-checked, and `revalidateTag` silently stops working.
|
|
10
66
|
incrementalCache: withRegionalCache(r2IncrementalCache, {
|
|
11
67
|
mode: 'long-lived',
|
|
12
|
-
bypassTagCacheOnCacheHit: true,
|
|
13
68
|
}),
|
|
14
|
-
queue: queueCache(
|
|
69
|
+
queue: queueCache(selfFetchQueue, {
|
|
15
70
|
regionalCacheTtlSec: 5,
|
|
16
71
|
waitForQueueAck: true,
|
|
17
72
|
}),
|
|
@@ -30,7 +85,6 @@ const cloudflareConfig = defineCloudflareConfig({
|
|
|
30
85
|
},
|
|
31
86
|
}),
|
|
32
87
|
enableCacheInterception: false,
|
|
33
|
-
cachePurge: purgeCache({ type: 'durableObject' }),
|
|
34
88
|
});
|
|
35
89
|
|
|
36
90
|
const config: OpenNextConfig = {
|