@serwist/turbopack 9.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/src/index.ts ADDED
@@ -0,0 +1,152 @@
1
+ // Workaround for Next.js + Turbopack, while plugins are still
2
+ // not supported. This relies on Next.js Route Handlers and file
3
+ // name determinism.
4
+ import path from "node:path";
5
+ import { type BuildResult, getFileManifestEntries, rebasePath } from "@serwist/build";
6
+ import { SerwistConfigError, validationErrorMap } from "@serwist/build/schema";
7
+ import { cyan, dim, yellow } from "kolorist";
8
+ import { NextResponse } from "next/server.js";
9
+ import { z } from "zod";
10
+ import { injectManifestOptions } from "./index.schema.js";
11
+ import { logger } from "./lib/index.js";
12
+ import type { InjectManifestOptions, InjectManifestOptionsComplete } from "./types.js";
13
+
14
+ // TODO(workarond): `esbuild` doesn't load when in Turbopack production
15
+ const esbuild = import("esbuild-wasm");
16
+
17
+ const logSerwistResult = (filePath: string, buildResult: Pick<BuildResult, "count" | "size" | "warnings">) => {
18
+ const { count, size, warnings } = buildResult;
19
+ const hasWarnings = warnings && warnings.length > 0;
20
+ // The route is reinitiated for each `path` param, so we only log results
21
+ // if we're prerendering for sw.js.
22
+ if (filePath === "sw.js" && (hasWarnings || count > 0)) {
23
+ logger[hasWarnings ? "warn" : "event"](
24
+ `${cyan(count)} precache entries ${dim(`(${(size / 1024).toFixed(2)} KiB)`)}${
25
+ hasWarnings ? `\n${yellow(["⚠ warnings", ...warnings.map((w) => ` ${w}`), ""].join("\n"))}` : ""
26
+ }`,
27
+ );
28
+ }
29
+ };
30
+
31
+ const validateGetManifestOptions = async (input: unknown): Promise<InjectManifestOptionsComplete> => {
32
+ const result = await injectManifestOptions.spa(input, {
33
+ error: validationErrorMap,
34
+ });
35
+ if (!result.success) {
36
+ throw new SerwistConfigError({
37
+ moduleName: "@serwist/turbopack",
38
+ message: z.prettifyError(result.error),
39
+ });
40
+ }
41
+ return result.data;
42
+ };
43
+
44
+ const isDev = process.env.NODE_ENV === "development";
45
+
46
+ const contentTypeMap: Record<string, string> = {
47
+ ".js": "application/javascript",
48
+ ".map": "application/json; charset=UTF-8",
49
+ };
50
+
51
+ /**
52
+ * Creates a Route Handler for Serwist files.
53
+ * @param options Options for {@linkcode getFileManifestEntries}.
54
+ */
55
+ export const createSerwistRoute = (options: InjectManifestOptions) => {
56
+ const dynamic = "force-static" as const,
57
+ dynamicParams = false as const,
58
+ revalidate = false as const;
59
+ const validation = validateGetManifestOptions(options).then((config) => {
60
+ return {
61
+ ...config,
62
+ disablePrecacheManifest: isDev,
63
+ additionalPrecacheEntries: isDev ? [] : config.additionalPrecacheEntries,
64
+ globIgnores: [
65
+ ...config.globIgnores,
66
+ // Make sure we leave swSrc out of the precache manifest.
67
+ rebasePath({
68
+ file: config.swSrc,
69
+ baseDirectory: config.globDirectory,
70
+ }),
71
+ ],
72
+ manifestTransforms: [
73
+ ...(config.manifestTransforms ?? []),
74
+ (manifestEntries) => {
75
+ const manifest = manifestEntries.map((m) => {
76
+ // Replace all references to "$(distDir)" with "$(assetPrefix)/_next/".
77
+ if (m.url.startsWith(config.nextConfig.distDir)) {
78
+ m.url = `${config.nextConfig.assetPrefix ?? ""}/_next/${m.url.slice(config.nextConfig.distDir.length)}`;
79
+ }
80
+ // Replace all references to public/ with "$(basePath)/".
81
+ if (m.url.startsWith("public/")) {
82
+ m.url = path.posix.join(config.nextConfig.basePath, m.url.slice(7));
83
+ }
84
+ return m;
85
+ });
86
+ return { manifest, warnings: [] };
87
+ },
88
+ ],
89
+ };
90
+ });
91
+ let map: Map<string, string> | null = null;
92
+ // NOTE: ALL FILES MUST HAVE DETERMINISTIC NAMES. THIS IS BECAUSE
93
+ // THE FOLLOWING MAP IS LOADED SEPARATELY FOR `generateStaticParams`
94
+ // AND EVERY `GET` REQUEST TO EACH OF THE FILES.
95
+ const loadMap = async (filePath: string) => {
96
+ const config = await validation;
97
+ const { count, size, manifestEntries, warnings } = await getFileManifestEntries(config);
98
+ // See https://github.com/GoogleChrome/workbox/issues/2230
99
+ const injectionPoint = config.injectionPoint || "";
100
+ const manifestString = manifestEntries === undefined ? "undefined" : JSON.stringify(manifestEntries, null, 2);
101
+ logSerwistResult(filePath, { count, size, warnings });
102
+ const result = await (await esbuild).build({
103
+ sourcemap: true,
104
+ format: "esm",
105
+ target: ["chrome64", "edge79", "firefox67", "opera51", "safari12"],
106
+ treeShaking: true,
107
+ minify: !isDev,
108
+ bundle: true,
109
+ ...config.esbuildOptions,
110
+ platform: "browser",
111
+ define: {
112
+ ...config.esbuildOptions.define,
113
+ ...(injectionPoint ? { [injectionPoint]: manifestString } : {}),
114
+ },
115
+ outdir: config.cwd,
116
+ write: false,
117
+ entryNames: "[name]",
118
+ // Asset and chunk names must be at the top, as our path is `/serwist/[path]`,
119
+ // not `/serwist/[...path]`, meaning that we can't resolve paths deeper
120
+ // than one level.
121
+ assetNames: "[name]-[hash]",
122
+ chunkNames: "[name]-[hash]",
123
+ entryPoints: [{ in: config.swSrc, out: "sw" }],
124
+ });
125
+ if (result.errors.length) {
126
+ console.error("Failed to build the service worker.", result.errors);
127
+ throw new Error();
128
+ }
129
+ if (result.warnings.length) {
130
+ console.warn(result.warnings);
131
+ }
132
+ return new Map(result.outputFiles.map((e) => [e.path, e.text]));
133
+ };
134
+ const generateStaticParams = async () => {
135
+ const config = await validation;
136
+ if (!map) map = await loadMap("root");
137
+ return [...map.keys().map((e) => ({ path: path.relative(config.cwd, e) }))];
138
+ };
139
+ const GET = async (_: Request, { params }: { params: Promise<{ path: string }> }) => {
140
+ // TODO: obviously, files get stale in development when we pull this off.
141
+ const { path: filePath } = await params;
142
+ const config = await validation;
143
+ if (!map) map = await loadMap(filePath);
144
+ return new NextResponse(map.get(path.join(config.cwd, filePath)), {
145
+ headers: {
146
+ "Content-Type": contentTypeMap[path.extname(filePath)] || "text/plain",
147
+ "Service-Worker-Allowed": "/",
148
+ },
149
+ });
150
+ };
151
+ return { dynamic, dynamicParams, revalidate, generateStaticParams, GET };
152
+ };
@@ -0,0 +1,274 @@
1
+ import type { RuntimeCaching } from "serwist";
2
+ import { CacheFirst, ExpirationPlugin, NetworkFirst, NetworkOnly, RangeRequestsPlugin, StaleWhileRevalidate } from "serwist";
3
+
4
+ export const PAGES_CACHE_NAME = {
5
+ rscPrefetch: "pages-rsc-prefetch",
6
+ rsc: "pages-rsc",
7
+ html: "pages",
8
+ } as const;
9
+
10
+ /**
11
+ * The default, recommended list of caching strategies for applications
12
+ * built with Next.js.
13
+ *
14
+ * @see https://serwist.pages.dev/docs/next/worker-exports#default-cache
15
+ */
16
+ export const defaultCache: RuntimeCaching[] =
17
+ process.env.NODE_ENV !== "production"
18
+ ? [
19
+ {
20
+ matcher: /.*/i,
21
+ handler: new NetworkOnly(),
22
+ },
23
+ ]
24
+ : [
25
+ {
26
+ matcher: /^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,
27
+ handler: new CacheFirst({
28
+ cacheName: "google-fonts-webfonts",
29
+ plugins: [
30
+ new ExpirationPlugin({
31
+ maxEntries: 4,
32
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 365 days
33
+ maxAgeFrom: "last-used",
34
+ }),
35
+ ],
36
+ }),
37
+ },
38
+ {
39
+ matcher: /^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,
40
+ handler: new StaleWhileRevalidate({
41
+ cacheName: "google-fonts-stylesheets",
42
+ plugins: [
43
+ new ExpirationPlugin({
44
+ maxEntries: 4,
45
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
46
+ maxAgeFrom: "last-used",
47
+ }),
48
+ ],
49
+ }),
50
+ },
51
+ {
52
+ matcher: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
53
+ handler: new StaleWhileRevalidate({
54
+ cacheName: "static-font-assets",
55
+ plugins: [
56
+ new ExpirationPlugin({
57
+ maxEntries: 4,
58
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
59
+ maxAgeFrom: "last-used",
60
+ }),
61
+ ],
62
+ }),
63
+ },
64
+ {
65
+ matcher: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
66
+ handler: new StaleWhileRevalidate({
67
+ cacheName: "static-image-assets",
68
+ plugins: [
69
+ new ExpirationPlugin({
70
+ maxEntries: 64,
71
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
72
+ maxAgeFrom: "last-used",
73
+ }),
74
+ ],
75
+ }),
76
+ },
77
+ {
78
+ matcher: /\/_next\/static.+\.js$/i,
79
+ handler: new CacheFirst({
80
+ cacheName: "next-static-js-assets",
81
+ plugins: [
82
+ new ExpirationPlugin({
83
+ maxEntries: 64,
84
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
85
+ maxAgeFrom: "last-used",
86
+ }),
87
+ ],
88
+ }),
89
+ },
90
+ {
91
+ matcher: /\/_next\/image\?url=.+$/i,
92
+ handler: new StaleWhileRevalidate({
93
+ cacheName: "next-image",
94
+ plugins: [
95
+ new ExpirationPlugin({
96
+ maxEntries: 64,
97
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
98
+ maxAgeFrom: "last-used",
99
+ }),
100
+ ],
101
+ }),
102
+ },
103
+ {
104
+ matcher: /\.(?:mp3|wav|ogg)$/i,
105
+ handler: new CacheFirst({
106
+ cacheName: "static-audio-assets",
107
+ plugins: [
108
+ new ExpirationPlugin({
109
+ maxEntries: 32,
110
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
111
+ maxAgeFrom: "last-used",
112
+ }),
113
+ new RangeRequestsPlugin(),
114
+ ],
115
+ }),
116
+ },
117
+ {
118
+ matcher: /\.(?:mp4|webm)$/i,
119
+ handler: new CacheFirst({
120
+ cacheName: "static-video-assets",
121
+ plugins: [
122
+ new ExpirationPlugin({
123
+ maxEntries: 32,
124
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
125
+ maxAgeFrom: "last-used",
126
+ }),
127
+ new RangeRequestsPlugin(),
128
+ ],
129
+ }),
130
+ },
131
+ {
132
+ matcher: /\.(?:js)$/i,
133
+ handler: new StaleWhileRevalidate({
134
+ cacheName: "static-js-assets",
135
+ plugins: [
136
+ new ExpirationPlugin({
137
+ maxEntries: 48,
138
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
139
+ maxAgeFrom: "last-used",
140
+ }),
141
+ ],
142
+ }),
143
+ },
144
+ {
145
+ matcher: /\.(?:css|less)$/i,
146
+ handler: new StaleWhileRevalidate({
147
+ cacheName: "static-style-assets",
148
+ plugins: [
149
+ new ExpirationPlugin({
150
+ maxEntries: 32,
151
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
152
+ maxAgeFrom: "last-used",
153
+ }),
154
+ ],
155
+ }),
156
+ },
157
+ {
158
+ matcher: /\/_next\/data\/.+\/.+\.json$/i,
159
+ handler: new NetworkFirst({
160
+ cacheName: "next-data",
161
+ plugins: [
162
+ new ExpirationPlugin({
163
+ maxEntries: 32,
164
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
165
+ maxAgeFrom: "last-used",
166
+ }),
167
+ ],
168
+ }),
169
+ },
170
+ {
171
+ matcher: /\.(?:json|xml|csv)$/i,
172
+ handler: new NetworkFirst({
173
+ cacheName: "static-data-assets",
174
+ plugins: [
175
+ new ExpirationPlugin({
176
+ maxEntries: 32,
177
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
178
+ maxAgeFrom: "last-used",
179
+ }),
180
+ ],
181
+ }),
182
+ },
183
+ {
184
+ // Exclude /api/auth/* to fix auth callback
185
+ // https://github.com/serwist/serwist/discussions/28
186
+ matcher: /\/api\/auth\/.*/,
187
+ handler: new NetworkOnly({
188
+ networkTimeoutSeconds: 10, // fallback to cache if API does not response within 10 seconds
189
+ }),
190
+ },
191
+ {
192
+ matcher: ({ sameOrigin, url: { pathname } }) => sameOrigin && pathname.startsWith("/api/"),
193
+ method: "GET",
194
+ handler: new NetworkFirst({
195
+ cacheName: "apis",
196
+ plugins: [
197
+ new ExpirationPlugin({
198
+ maxEntries: 16,
199
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
200
+ maxAgeFrom: "last-used",
201
+ }),
202
+ ],
203
+ networkTimeoutSeconds: 10, // fallback to cache if API does not response within 10 seconds
204
+ }),
205
+ },
206
+ {
207
+ matcher: ({ request, url: { pathname }, sameOrigin }) =>
208
+ request.headers.get("RSC") === "1" && request.headers.get("Next-Router-Prefetch") === "1" && sameOrigin && !pathname.startsWith("/api/"),
209
+ handler: new NetworkFirst({
210
+ cacheName: PAGES_CACHE_NAME.rscPrefetch,
211
+ plugins: [
212
+ new ExpirationPlugin({
213
+ maxEntries: 32,
214
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
215
+ }),
216
+ ],
217
+ }),
218
+ },
219
+ {
220
+ matcher: ({ request, url: { pathname }, sameOrigin }) => request.headers.get("RSC") === "1" && sameOrigin && !pathname.startsWith("/api/"),
221
+ handler: new NetworkFirst({
222
+ cacheName: PAGES_CACHE_NAME.rsc,
223
+ plugins: [
224
+ new ExpirationPlugin({
225
+ maxEntries: 32,
226
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
227
+ }),
228
+ ],
229
+ }),
230
+ },
231
+ {
232
+ matcher: ({ request, url: { pathname }, sameOrigin }) =>
233
+ request.headers.get("Content-Type")?.includes("text/html") && sameOrigin && !pathname.startsWith("/api/"),
234
+ handler: new NetworkFirst({
235
+ cacheName: PAGES_CACHE_NAME.html,
236
+ plugins: [
237
+ new ExpirationPlugin({
238
+ maxEntries: 32,
239
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
240
+ }),
241
+ ],
242
+ }),
243
+ },
244
+ {
245
+ matcher: ({ url: { pathname }, sameOrigin }) => sameOrigin && !pathname.startsWith("/api/"),
246
+ handler: new NetworkFirst({
247
+ cacheName: "others",
248
+ plugins: [
249
+ new ExpirationPlugin({
250
+ maxEntries: 32,
251
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
252
+ }),
253
+ ],
254
+ }),
255
+ },
256
+ {
257
+ matcher: ({ sameOrigin }) => !sameOrigin,
258
+ handler: new NetworkFirst({
259
+ cacheName: "cross-origin",
260
+ plugins: [
261
+ new ExpirationPlugin({
262
+ maxEntries: 32,
263
+ maxAgeSeconds: 60 * 60, // 1 hour
264
+ }),
265
+ ],
266
+ networkTimeoutSeconds: 10,
267
+ }),
268
+ },
269
+ {
270
+ matcher: /.*/i,
271
+ method: "GET",
272
+ handler: new NetworkOnly(),
273
+ },
274
+ ];
@@ -0,0 +1,61 @@
1
+ import type { BuildOptions } from "esbuild-wasm";
2
+
3
+ export const SUPPORTED_ESBUILD_OPTIONS = [
4
+ // CommonOptions
5
+ "sourcemap",
6
+ "legalComments",
7
+ "sourceRoot",
8
+ "sourcesContent",
9
+ "format",
10
+ "globalName",
11
+ "target",
12
+ "supported",
13
+ "define",
14
+ "treeShaking",
15
+ "minify",
16
+ "mangleProps",
17
+ "reserveProps",
18
+ "mangleQuoted",
19
+ "mangleCache",
20
+ "drop",
21
+ "dropLabels",
22
+ "minifyWhitespace",
23
+ "minifyIdentifiers",
24
+ "minifySyntax",
25
+ "lineLimit",
26
+ "charset",
27
+ "ignoreAnnotations",
28
+ "jsx",
29
+ "jsxFactory",
30
+ "jsxFragment",
31
+ "jsxImportSource",
32
+ "jsxDev",
33
+ "jsxSideEffects",
34
+ "pure",
35
+ "keepNames",
36
+ "absPaths",
37
+ "color",
38
+ "logLevel",
39
+ "logLimit",
40
+ "logOverride",
41
+ "tsconfigRaw",
42
+ // BuildOptions
43
+ "bundle",
44
+ "splitting",
45
+ "preserveSymlinks",
46
+ "external",
47
+ "packages",
48
+ "alias",
49
+ "loader",
50
+ "resolveExtensions",
51
+ "mainFields",
52
+ "conditions",
53
+ "allowOverwrite",
54
+ "tsconfig",
55
+ "outExtension",
56
+ "publicPath",
57
+ "inject",
58
+ "banner",
59
+ "footer",
60
+ "plugins",
61
+ ] as const satisfies readonly (keyof BuildOptions)[];
@@ -0,0 +1,16 @@
1
+ import type { Serwist } from "@serwist/window";
2
+ import { createContext, useContext } from "react";
3
+
4
+ export interface SerwistContextValues {
5
+ serwist: Serwist | null;
6
+ }
7
+
8
+ export const SerwistContext = createContext<SerwistContextValues>(null!);
9
+
10
+ export const useSerwist = () => {
11
+ const context = useContext(SerwistContext);
12
+ if (!context) {
13
+ throw new Error("[useSerwist]: 'SerwistContext' is not available.");
14
+ }
15
+ return context;
16
+ };
@@ -0,0 +1,3 @@
1
+ import * as logger from "./logger.js";
2
+
3
+ export { logger };
@@ -0,0 +1,58 @@
1
+ import { createRequire } from "node:module";
2
+ import { bold, green, red, white, yellow } from "kolorist";
3
+ import semver from "semver";
4
+
5
+ const require = createRequire(import.meta.url);
6
+
7
+ const LOGGING_SPACE_PREFIX = semver.gte(require("next/package.json").version, "16.0.0") ? "" : " ";
8
+
9
+ export type LoggingMethods = "wait" | "error" | "warn" | "info" | "event";
10
+
11
+ const prefixedLog = (prefixType: LoggingMethods, ...message: any[]) => {
12
+ let prefix: string;
13
+ let consoleMethod: keyof Console;
14
+
15
+ switch (prefixType) {
16
+ case "wait":
17
+ prefix = `${white(bold("○"))} (serwist)`;
18
+ consoleMethod = "log";
19
+ break;
20
+ case "error":
21
+ prefix = `${red(bold("X"))} (serwist)`;
22
+ consoleMethod = "error";
23
+ break;
24
+ case "warn":
25
+ prefix = `${yellow(bold("⚠"))} (serwist)`;
26
+ consoleMethod = "warn";
27
+ break;
28
+ case "info":
29
+ prefix = `${white(bold("○"))} (serwist)`;
30
+ consoleMethod = "log";
31
+ break;
32
+ case "event":
33
+ prefix = `${green(bold("✓"))} (serwist)`;
34
+ consoleMethod = "log";
35
+ break;
36
+ }
37
+
38
+ if ((message[0] === "" || message[0] === undefined) && message.length === 1) {
39
+ message.shift();
40
+ }
41
+
42
+ // If there's no message, don't print the prefix but a new line
43
+ if (message.length === 0) {
44
+ console[consoleMethod]("");
45
+ } else {
46
+ console[consoleMethod](`${LOGGING_SPACE_PREFIX}${prefix}`, ...message);
47
+ }
48
+ };
49
+
50
+ export const wait = (...message: any[]) => prefixedLog("wait", ...message);
51
+
52
+ export const error = (...message: any[]) => prefixedLog("error", ...message);
53
+
54
+ export const warn = (...message: any[]) => prefixedLog("warn", ...message);
55
+
56
+ export const info = (...message: any[]) => prefixedLog("info", ...message);
57
+
58
+ export const event = (...message: any[]) => prefixedLog("event", ...message);
@@ -0,0 +1,4 @@
1
+ export const generateGlobPatterns = (distDir: string) => [
2
+ `${distDir}static/**/*.{js,css,html,ico,apng,png,avif,jpg,jpeg,jfif,pjpeg,pjp,gif,svg,webp,json,webmanifest}`,
3
+ "public/**/*",
4
+ ];
package/src/types.ts ADDED
@@ -0,0 +1,79 @@
1
+ import type {
2
+ BasePartial,
3
+ BaseResolved,
4
+ GlobPartial,
5
+ GlobResolved,
6
+ InjectPartial,
7
+ InjectResolved,
8
+ OptionalGlobDirectoryPartial,
9
+ RequiredGlobDirectoryResolved,
10
+ } from "@serwist/build";
11
+ import type { Prettify, Require } from "@serwist/utils";
12
+ import type { BuildOptions } from "esbuild-wasm";
13
+ import type { SUPPORTED_ESBUILD_OPTIONS } from "./lib/constants.js";
14
+ import type { NextConfig as CompleteNextConfig } from "next";
15
+
16
+ export type EsbuildSupportedOptions = (typeof SUPPORTED_ESBUILD_OPTIONS)[number];
17
+
18
+ export type EsbuildOptions = Pick<BuildOptions, EsbuildSupportedOptions>;
19
+
20
+ export interface NextConfig extends Pick<CompleteNextConfig, "basePath" | "distDir"> {
21
+ /**
22
+ * The Next.js `assetPrefix` config option.
23
+ *
24
+ * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix
25
+ */
26
+ assetPrefix?: string;
27
+ /**
28
+ * The Next.js `basePath` config option.
29
+ *
30
+ * @default "/"
31
+ * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath
32
+ */
33
+ basePath?: string;
34
+ /**
35
+ * The Next.js `distDir` config option.
36
+ *
37
+ * @default ".next"
38
+ * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/distDir
39
+ */
40
+ distDir?: string;
41
+ }
42
+
43
+ export interface TurboPartial {
44
+ /**
45
+ * The path to your working directory.
46
+ *
47
+ * @default process.cwd()
48
+ */
49
+ cwd?: string;
50
+ /**
51
+ * A copy of your Next.js configuration. You must check
52
+ * if any option you've configured is needed by Serwist
53
+ * to ensure expected behavior.
54
+ *
55
+ * The following options are currently needed: `assetPrefix`,
56
+ * `basePath`, `distDir`.
57
+ */
58
+ nextConfig: Prettify<NextConfig>;
59
+ /**
60
+ * Options to configure the esbuild instance used to bundle
61
+ * the service worker.
62
+ */
63
+ esbuildOptions?: EsbuildOptions;
64
+ }
65
+
66
+ export interface TurboResolved extends Require<TurboPartial, "cwd" | "esbuildOptions"> {
67
+ nextConfig: Require<NextConfig, "basePath" | "distDir">;
68
+ }
69
+
70
+ export type InjectManifestOptions = Prettify<
71
+ Omit<BasePartial & GlobPartial & InjectPartial & OptionalGlobDirectoryPartial & TurboPartial, "disablePrecacheManifest">
72
+ >;
73
+
74
+ export type InjectManifestOptionsComplete = Prettify<
75
+ Omit<
76
+ Require<BaseResolved, "dontCacheBustURLsMatching"> & GlobResolved & InjectResolved & RequiredGlobDirectoryResolved & TurboResolved,
77
+ "disablePrecacheManifest"
78
+ >
79
+ >;