@alxia/react-router 0.9.0 → 0.10.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 +126 -13
- package/dist/chunks/index-59vhfj6n.js +10 -0
- package/dist/chunks/index-59vhfj6n.js.map +10 -0
- package/dist/chunks/index-5gqcpyyg.js +34 -0
- package/dist/chunks/index-5gqcpyyg.js.map +10 -0
- package/dist/chunks/{index-zqa30gr7.js → index-9xv2a8et.js} +7 -38
- package/dist/chunks/index-9xv2a8et.js.map +11 -0
- package/dist/chunks/index-mppz0806.js +119 -0
- package/dist/chunks/index-mppz0806.js.map +11 -0
- package/dist/chunks/index-rfr02vg4.js +40 -0
- package/dist/chunks/index-rfr02vg4.js.map +10 -0
- package/dist/chunks/index-zdbqzcjp.js +97 -0
- package/dist/chunks/index-zdbqzcjp.js.map +12 -0
- package/dist/pwa/build/build-worker.d.ts +41 -0
- package/dist/pwa/build/build-worker.d.ts.map +1 -0
- package/dist/pwa/build/index.d.ts +9 -0
- package/dist/pwa/build/index.d.ts.map +1 -0
- package/dist/pwa/build/index.js +9 -0
- package/dist/pwa/build/index.js.map +9 -0
- package/dist/pwa/build/precache.d.ts +17 -0
- package/dist/pwa/build/precache.d.ts.map +1 -0
- package/dist/pwa/index.js +34 -134
- package/dist/pwa/index.js.map +4 -8
- package/dist/pwa/react/index.js +1 -1
- package/dist/pwa/worker/index.d.ts +9 -0
- package/dist/pwa/worker/index.d.ts.map +1 -0
- package/dist/pwa/worker/index.js +144 -0
- package/dist/pwa/worker/index.js.map +12 -0
- package/dist/pwa/worker/injected.d.ts +15 -0
- package/dist/pwa/worker/injected.d.ts.map +1 -0
- package/dist/pwa/worker/plan.d.ts +65 -0
- package/dist/pwa/worker/plan.d.ts.map +1 -0
- package/dist/pwa/worker/scope.d.ts +18 -0
- package/dist/pwa/worker/scope.d.ts.map +1 -0
- package/dist/pwa/worker/start-worker.d.ts +17 -0
- package/dist/pwa/worker/start-worker.d.ts.map +1 -0
- package/dist/vite/index.d.ts +10 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +49 -3
- package/dist/vite/index.js.map +6 -5
- package/dist/vite/runtime.d.ts +1 -1
- package/dist/vite/runtime.d.ts.map +1 -1
- package/dist/vite/worker.d.ts +16 -0
- package/dist/vite/worker.d.ts.map +1 -0
- package/docs/README.md +1 -1
- package/docs/guide/how-it-works.md +7 -1
- package/docs/guide/pwa.md +372 -211
- package/docs/roadmap.md +19 -5
- package/docs/troubleshooting.md +208 -3
- package/package.json +46 -4
- package/dist/chunks/index-zqa30gr7.js.map +0 -12
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SERVICE_WORKER_URL2
|
|
3
|
+
} from "./index-rfr02vg4.js";
|
|
4
|
+
|
|
5
|
+
// src/pwa/model/manifest.ts
|
|
6
|
+
var MANIFEST_PATH2 = "/manifest.webmanifest";
|
|
7
|
+
var MANIFEST_HEADERS2 = {
|
|
8
|
+
"content-type": "application/manifest+json; charset=utf-8",
|
|
9
|
+
"cache-control": "public, max-age=3600",
|
|
10
|
+
vary: "Accept-Language",
|
|
11
|
+
"content-security-policy": "default-src 'none'; frame-ancestors 'none'"
|
|
12
|
+
};
|
|
13
|
+
function manifestHref2(language, path = MANIFEST_PATH2) {
|
|
14
|
+
return `${path}?lang=${encodeURIComponent(language)}`;
|
|
15
|
+
}
|
|
16
|
+
function manifestLanguage2(url, supported, fallback) {
|
|
17
|
+
const requested = url.searchParams.get("lang");
|
|
18
|
+
return supported.find((language) => language === requested) ?? fallback;
|
|
19
|
+
}
|
|
20
|
+
var MINIMAL_2023_ICONS2 = Object.freeze([
|
|
21
|
+
{ src: "/pwa-64x64.png", sizes: "64x64", type: "image/png" },
|
|
22
|
+
{ src: "/pwa-192x192.png", sizes: "192x192", type: "image/png" },
|
|
23
|
+
{ src: "/pwa-512x512.png", sizes: "512x512", type: "image/png" },
|
|
24
|
+
{
|
|
25
|
+
src: "/maskable-icon-512x512.png",
|
|
26
|
+
sizes: "512x512",
|
|
27
|
+
type: "image/png",
|
|
28
|
+
purpose: "maskable"
|
|
29
|
+
}
|
|
30
|
+
].map((icon) => Object.freeze(icon)));
|
|
31
|
+
function webAppManifest2(options) {
|
|
32
|
+
return {
|
|
33
|
+
id: options.id ?? "/",
|
|
34
|
+
name: options.name,
|
|
35
|
+
short_name: options.shortName ?? options.name,
|
|
36
|
+
description: options.description,
|
|
37
|
+
lang: options.lang,
|
|
38
|
+
dir: options.dir ?? "ltr",
|
|
39
|
+
start_url: options.startUrl ?? "/",
|
|
40
|
+
scope: options.scope ?? "/",
|
|
41
|
+
display: options.display ?? "standalone",
|
|
42
|
+
theme_color: options.themeColor,
|
|
43
|
+
background_color: options.backgroundColor,
|
|
44
|
+
...options.categories && { categories: [...options.categories] },
|
|
45
|
+
icons: (options.icons ?? MINIMAL_2023_ICONS2).map((icon) => ({ ...icon }))
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/pwa/model/caching.ts
|
|
50
|
+
var STATIC_EXTENSION = /\.(?:js|mjs|css|woff2?|ttf|otf|svg|png|jpe?g|webp|avif|gif|ico)$/i;
|
|
51
|
+
var underAssets = (path) => path.startsWith("/assets/");
|
|
52
|
+
function cachingFor2(request, origin, options = {}) {
|
|
53
|
+
if (request.method !== "GET")
|
|
54
|
+
return "none";
|
|
55
|
+
if (request.mode === "navigate")
|
|
56
|
+
return "navigation";
|
|
57
|
+
const url = new URL(request.url);
|
|
58
|
+
if (url.origin !== origin)
|
|
59
|
+
return "none";
|
|
60
|
+
if (request.headers.has("authorization"))
|
|
61
|
+
return "none";
|
|
62
|
+
if (url.search)
|
|
63
|
+
return "none";
|
|
64
|
+
const path = url.pathname;
|
|
65
|
+
if (path.endsWith(".data") || path === "/__manifest" || path === (options.serviceWorkerUrl ?? options.contract?.serviceWorkerUrl ?? SERVICE_WORKER_URL2) || path === (options.manifestPath ?? MANIFEST_PATH2) || options.never?.(path)) {
|
|
66
|
+
return "none";
|
|
67
|
+
}
|
|
68
|
+
if (request.destination === "document" || request.destination === "iframe")
|
|
69
|
+
return "none";
|
|
70
|
+
if (!STATIC_EXTENSION.test(path))
|
|
71
|
+
return "none";
|
|
72
|
+
return (options.immutable ?? underAssets)(path) ? "immutable" : "static";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/pwa/model/storable.ts
|
|
76
|
+
var STATIC_CONTENT_TYPE = /^(?:(?:text|application)\/(?:javascript|x-javascript|ecmascript)|text\/css|font\/[\w.+-]+|application\/(?:font-woff2?|x-font-[\w.+-]+|vnd\.ms-fontobject)|image\/[\w.+-]+)$/i;
|
|
77
|
+
function isStorable2(response) {
|
|
78
|
+
if (response.status !== 200)
|
|
79
|
+
return false;
|
|
80
|
+
if (response.type !== "basic" && response.type !== "default")
|
|
81
|
+
return false;
|
|
82
|
+
const contentType = (response.headers.get("content-type") ?? "").split(";")[0]?.trim();
|
|
83
|
+
if (!contentType || !STATIC_CONTENT_TYPE.test(contentType))
|
|
84
|
+
return false;
|
|
85
|
+
const cacheControl = response.headers.get("cache-control") ?? "";
|
|
86
|
+
if (!/\bpublic\b/i.test(cacheControl))
|
|
87
|
+
return false;
|
|
88
|
+
if (/\b(?:no-store|private)\b/i.test(cacheControl))
|
|
89
|
+
return false;
|
|
90
|
+
const vary = response.headers.get("vary") ?? "";
|
|
91
|
+
return !/(?:^|,)\s*(?:\*|cookie|authorization)\s*(?:,|$)/i.test(vary);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export { MANIFEST_PATH2, MANIFEST_HEADERS2, manifestHref2, manifestLanguage2, MINIMAL_2023_ICONS2, webAppManifest2, cachingFor2, isStorable2 };
|
|
95
|
+
|
|
96
|
+
//# debugId=E5DD035F8EB2F4B164756E2164756E21
|
|
97
|
+
//# sourceMappingURL=index-zdbqzcjp.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/pwa/model/manifest.ts", "../src/pwa/model/caching.ts", "../src/pwa/model/storable.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/** Where the server serves the manifest, and the document head links it. */\nexport const MANIFEST_PATH = '/manifest.webmanifest';\n\n/**\n * Cacheable for an hour, like the icons; the language travels in `?lang=`.\n * Its own policy, which loads nothing: the pages' one carries a nonce, and\n * a nonce never goes in a response a cache may keep.\n */\nexport const MANIFEST_HEADERS = {\n\t'content-type': 'application/manifest+json; charset=utf-8',\n\t'cache-control': 'public, max-age=3600',\n\tvary: 'Accept-Language',\n\t'content-security-policy': \"default-src 'none'; frame-ancestors 'none'\",\n} as const;\n\n/**\n * The manifest's URL for a page in `language`. A browser fetches the\n * manifest without cookies, so a `language` cookie would not reach it: the\n * page names its language in the query instead.\n */\nexport function manifestHref(\n\tlanguage: string,\n\tpath: string = MANIFEST_PATH,\n): string {\n\treturn `${path}?lang=${encodeURIComponent(language)}`;\n}\n\n/**\n * `?lang=` when it names one of `supported`, else `fallback`: the request's\n * Accept-Language, never its cookie, so `Vary: Accept-Language` holds.\n */\nexport function manifestLanguage<L extends string>(\n\turl: URL,\n\tsupported: readonly L[],\n\tfallback: L,\n): L {\n\tconst requested = url.searchParams.get('lang');\n\treturn supported.find((language) => language === requested) ?? fallback;\n}\n\nexport type ManifestIcon = {\n\tsrc: string;\n\tsizes: string;\n\ttype: string;\n\tpurpose?: 'any' | 'maskable' | 'monochrome';\n};\n\n/**\n * The four icons `@vite-pwa/assets-generator`'s `minimal2023Preset` writes\n * to `public/`: 64, 192 and 512 pixels, and a maskable 512.\n */\nexport const MINIMAL_2023_ICONS: readonly ManifestIcon[] = Object.freeze(\n\t[\n\t\t{ src: '/pwa-64x64.png', sizes: '64x64', type: 'image/png' },\n\t\t{ src: '/pwa-192x192.png', sizes: '192x192', type: 'image/png' },\n\t\t{ src: '/pwa-512x512.png', sizes: '512x512', type: 'image/png' },\n\t\t{\n\t\t\tsrc: '/maskable-icon-512x512.png',\n\t\t\tsizes: '512x512',\n\t\t\ttype: 'image/png',\n\t\t\tpurpose: 'maskable' as const,\n\t\t},\n\t].map((icon) => Object.freeze(icon)),\n);\n\nexport interface WebAppManifestOptions {\n\tname: string;\n\t/** `name` by default. */\n\tshortName?: string;\n\tdescription: string;\n\t/** The language of `name` and `description`. */\n\tlang: string;\n\t/** `'ltr'` by default. */\n\tdir?: 'ltr' | 'rtl' | 'auto';\n\tthemeColor: string;\n\tbackgroundColor: string;\n\tcategories?: readonly string[];\n\t/** `MINIMAL_2023_ICONS` by default. */\n\ticons?: readonly ManifestIcon[];\n\t/** `'/'` by default: the same in every language, so a language switch never makes a second app. */\n\tid?: string;\n\t/** `'/'` by default. */\n\tstartUrl?: string;\n\t/** `'/'` by default. */\n\tscope?: string;\n\t/** `'standalone'` by default. */\n\tdisplay?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';\n}\n\n/** The web app manifest's JSON, with its snake_case keys. */\nexport type WebAppManifest = {\n\tid: string;\n\tname: string;\n\tshort_name: string;\n\tdescription: string;\n\tlang: string;\n\tdir: 'ltr' | 'rtl' | 'auto';\n\tstart_url: string;\n\tscope: string;\n\tdisplay: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser';\n\ttheme_color: string;\n\tbackground_color: string;\n\tcategories?: string[];\n\ticons: ManifestIcon[];\n};\n\n/**\n * A web app manifest from the app's own (translated) texts and colours.\n * `id`, `start_url` and `scope` default to `'/'` whatever the language.\n */\nexport function webAppManifest(options: WebAppManifestOptions): WebAppManifest {\n\treturn {\n\t\tid: options.id ?? '/',\n\t\tname: options.name,\n\t\tshort_name: options.shortName ?? options.name,\n\t\tdescription: options.description,\n\t\tlang: options.lang,\n\t\tdir: options.dir ?? 'ltr',\n\t\tstart_url: options.startUrl ?? '/',\n\t\tscope: options.scope ?? '/',\n\t\tdisplay: options.display ?? 'standalone',\n\t\ttheme_color: options.themeColor,\n\t\tbackground_color: options.backgroundColor,\n\t\t...(options.categories && { categories: [...options.categories] }),\n\t\ticons: (options.icons ?? MINIMAL_2023_ICONS).map((icon) => ({ ...icon })),\n\t};\n}\n",
|
|
6
|
+
"import { MANIFEST_PATH } from './manifest';\nimport { SERVICE_WORKER_URL, type WorkerContract } from './worker-contract';\n\n/**\n * Which requests the service worker caches, and how. Pure, so that what is\n * never cached is tested, not hoped for.\n *\n * - `navigation`: a page load. Always from the network, never stored; the\n * offline page answers only when the network fails.\n * - `immutable`: a hashed bundle: cache-first.\n * - `static`: another same-origin static file (icon, sprite, logo):\n * stale-while-revalidate.\n * - `none`: left to the browser, untouched: every non-GET, any other\n * origin, React Router's `.data` and `/__manifest`, the worker and the\n * manifest themselves, the app's own `never` paths, and anything carrying\n * credentials.\n */\nexport type Caching = 'navigation' | 'immutable' | 'static' | 'none';\n\n/** What a `Request` exposes that the decision reads. */\nexport interface RequestFacts {\n\treadonly method: string;\n\treadonly url: string;\n\treadonly mode: string;\n\treadonly destination: string;\n\treadonly headers: Pick<Headers, 'has'>;\n}\n\nexport interface CachingOptions {\n\t/**\n\t * The worker's own path, never cached. Wins over `contract`;\n\t * `SERVICE_WORKER_URL` when neither is given.\n\t */\n\tserviceWorkerUrl?: string;\n\t/** The app's contract, whose `serviceWorkerUrl` is never cached. */\n\tcontract?: Pick<WorkerContract, 'serviceWorkerUrl'>;\n\t/** The web app manifest's path, never cached. `MANIFEST_PATH` by default. */\n\tmanifestPath?: string;\n\t/** Paths of the app answered fresh every time, such as `(p) => p.startsWith('/api/')`. */\n\tnever?: (path: string) => boolean;\n\t/**\n\t * Which static paths are immutable (cache-first) rather than static.\n\t * `(path) => path.startsWith('/assets/')` by default, as `serveClient`\n\t * serves them.\n\t */\n\timmutable?: (path: string) => boolean;\n}\n\nconst STATIC_EXTENSION =\n\t/\\.(?:js|mjs|css|woff2?|ttf|otf|svg|png|jpe?g|webp|avif|gif|ico)$/i;\n\nconst underAssets = (path: string) => path.startsWith('/assets/');\n\n/** How the worker answers `request`, for an app served at `origin`. */\nexport function cachingFor(\n\trequest: RequestFacts,\n\torigin: string,\n\toptions: CachingOptions = {},\n): Caching {\n\tif (request.method !== 'GET') return 'none';\n\tif (request.mode === 'navigate') return 'navigation';\n\tconst url = new URL(request.url);\n\tif (url.origin !== origin) return 'none';\n\tif (request.headers.has('authorization')) return 'none';\n\tif (url.search) return 'none';\n\tconst path = url.pathname;\n\tif (\n\t\tpath.endsWith('.data') || // React Router single fetch: loader data\n\t\tpath === '/__manifest' || // React Router route discovery\n\t\tpath ===\n\t\t\t(options.serviceWorkerUrl ??\n\t\t\t\toptions.contract?.serviceWorkerUrl ??\n\t\t\t\tSERVICE_WORKER_URL) ||\n\t\tpath === (options.manifestPath ?? MANIFEST_PATH) ||\n\t\toptions.never?.(path)\n\t) {\n\t\treturn 'none';\n\t}\n\tif (request.destination === 'document' || request.destination === 'iframe')\n\t\treturn 'none';\n\tif (!STATIC_EXTENSION.test(path)) return 'none';\n\treturn (options.immutable ?? underAssets)(path) ? 'immutable' : 'static';\n}\n",
|
|
7
|
+
"/**\n * The content types of the static extensions: scripts, styles, fonts and\n * images (SVG and icons included). A page, JSON or anything else served\n * under a static-looking path is refused all the same.\n */\nconst STATIC_CONTENT_TYPE =\n\t/^(?:(?:text|application)\\/(?:javascript|x-javascript|ecmascript)|text\\/css|font\\/[\\w.+-]+|application\\/(?:font-woff2?|x-font-[\\w.+-]+|vnd\\.ms-fontobject)|image\\/[\\w.+-]+)$/i;\n\n/**\n * Whether a response may be stored: a full, same-origin 200 of a static\n * content type, that the server marked `public` (alxia does on every\n * static file it serves; a route answering an image, a user's photo, does\n * not), not private nor no-store, and that does not vary on who asks.\n */\nexport function isStorable(response: Response): boolean {\n\tif (response.status !== 200) return false;\n\tif (response.type !== 'basic' && response.type !== 'default') return false;\n\tconst contentType = (response.headers.get('content-type') ?? '')\n\t\t.split(';')[0]\n\t\t?.trim();\n\tif (!contentType || !STATIC_CONTENT_TYPE.test(contentType)) return false;\n\tconst cacheControl = response.headers.get('cache-control') ?? '';\n\tif (!/\\bpublic\\b/i.test(cacheControl)) return false;\n\tif (/\\b(?:no-store|private)\\b/i.test(cacheControl)) return false;\n\tconst vary = response.headers.get('vary') ?? '';\n\treturn !/(?:^|,)\\s*(?:\\*|cookie|authorization)\\s*(?:,|$)/i.test(vary);\n}\n"
|
|
8
|
+
],
|
|
9
|
+
"mappings": "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",
|
|
10
|
+
"debugId": "E5DD035F8EB2F4B164756E2164756E21",
|
|
11
|
+
"names": []
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PrecacheEntry } from '../model/precache-list';
|
|
2
|
+
import { type WorkerContract } from '../model/worker-contract';
|
|
3
|
+
export interface BuildWorkerOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The worker's source, relative to `root`: `app/service-worker.ts`. Named
|
|
6
|
+
* `file`, not `entry`: `reveal` reads `alxia({ entry })`.
|
|
7
|
+
*/
|
|
8
|
+
file: string;
|
|
9
|
+
/** `process.cwd()` by default. */
|
|
10
|
+
root?: string;
|
|
11
|
+
/** The client build, relative to `root`: `build/client` by default. */
|
|
12
|
+
client?: string;
|
|
13
|
+
/** Where the worker is written and which offline page is precached. */
|
|
14
|
+
contract?: Pick<WorkerContract, 'serviceWorkerUrl' | 'offlineUrl'>;
|
|
15
|
+
/** Precache the offline page, which must then exist. `true` by default. */
|
|
16
|
+
offline?: boolean;
|
|
17
|
+
/** More files of `assets/` to precache, such as fonts: the app's regex. */
|
|
18
|
+
precacheAssets?: RegExp;
|
|
19
|
+
/** `true` by default. */
|
|
20
|
+
minify?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface WorkerBuild {
|
|
23
|
+
/** The absolute path of the worker written. */
|
|
24
|
+
file: string;
|
|
25
|
+
precache: PrecacheEntry[];
|
|
26
|
+
/** The precached files' size, before compression. */
|
|
27
|
+
precacheBytes: number;
|
|
28
|
+
/** The worker's own size. */
|
|
29
|
+
bytes: number;
|
|
30
|
+
}
|
|
31
|
+
/** Not `requireBun` of `vite/`: `/pwa/build` imports Node's built-ins only. */
|
|
32
|
+
export declare function assertBun(onBun?: boolean): void;
|
|
33
|
+
/**
|
|
34
|
+
* Bundles the worker (Workbox included) into the client build, after
|
|
35
|
+
* `react-router build`, with the precache list written in: the offline page
|
|
36
|
+
* by its content, every route's code and `precacheAssets`. A new build
|
|
37
|
+
* changes the list, so the worker's bytes, so the browser installs it.
|
|
38
|
+
* Runs on Bun; the only imports of this module are Node's built-ins.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildWorker(options: BuildWorkerOptions): Promise<WorkerBuild>;
|
|
41
|
+
//# sourceMappingURL=build-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-worker.d.ts","sourceRoot":"","sources":["../../../src/pwa/build/build-worker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,0BAA0B,CAAC;AAIlC,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,kBAAkB,GAAG,YAAY,CAAC,CAAC;IACnE,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC3B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;CACd;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CACxB,KAAK,UAAsD,GACzD,IAAI,CAKN;AAoBD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,WAAW,CAAC,CAgEtB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@alxia/react-router/pwa/build`: bundles the service worker into the
|
|
3
|
+
* client build with its precache list. Run it on Bun, after
|
|
4
|
+
* `react-router build`. Node's built-ins are its only imports, and Bun's
|
|
5
|
+
* global is read inside the function, never at load.
|
|
6
|
+
*/
|
|
7
|
+
export type { BuildWorkerOptions, WorkerBuild } from './build-worker';
|
|
8
|
+
export { buildWorker } from './build-worker';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pwa/build/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type PrecacheEntry } from '../model/precache-list';
|
|
2
|
+
/** The one React Router browser manifest among the names in build/client/assets. */
|
|
3
|
+
export declare function browserManifestFile(files: readonly string[]): string;
|
|
4
|
+
/** A file's revision: the first 16 hex characters of its sha256. */
|
|
5
|
+
export declare function revisionOf(bytes: Uint8Array): string;
|
|
6
|
+
/**
|
|
7
|
+
* The worker's precache list: the offline page (revisioned by its content),
|
|
8
|
+
* every route's code, then the asset files `include` matches. Each URL once,
|
|
9
|
+
* the first kept.
|
|
10
|
+
*/
|
|
11
|
+
export declare function workerPrecache(input: {
|
|
12
|
+
manifestSource: string;
|
|
13
|
+
assetFiles: readonly string[];
|
|
14
|
+
offline?: PrecacheEntry | undefined;
|
|
15
|
+
include?: RegExp | undefined;
|
|
16
|
+
}): PrecacheEntry[];
|
|
17
|
+
//# sourceMappingURL=precache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precache.d.ts","sourceRoot":"","sources":["../../../src/pwa/build/precache.ts"],"names":[],"mappings":"AACA,OAAO,EAEN,KAAK,aAAa,EAGlB,MAAM,wBAAwB,CAAC;AAEhC,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CASpE;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,aAAa,EAAE,CAQlB"}
|
package/dist/pwa/index.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
MANIFEST_PATH2,
|
|
3
|
+
MANIFEST_HEADERS2,
|
|
4
|
+
manifestHref2,
|
|
5
|
+
manifestLanguage2,
|
|
6
|
+
MINIMAL_2023_ICONS2,
|
|
7
|
+
webAppManifest2,
|
|
8
|
+
cachingFor2,
|
|
9
|
+
isStorable2
|
|
10
|
+
} from "../chunks/index-zdbqzcjp.js";
|
|
11
|
+
import {
|
|
6
12
|
watchForUpdates2,
|
|
7
13
|
createUpdater2,
|
|
8
14
|
afterLoad2,
|
|
@@ -10,77 +16,18 @@ import {
|
|
|
10
16
|
UPDATE_LATER_KEY2,
|
|
11
17
|
createUpdateNotice2,
|
|
12
18
|
sessionStore2
|
|
13
|
-
} from "../chunks/index-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
function manifestLanguage(url, supported, fallback) {
|
|
27
|
-
const requested = url.searchParams.get("lang");
|
|
28
|
-
return supported.find((language) => language === requested) ?? fallback;
|
|
29
|
-
}
|
|
30
|
-
var MINIMAL_2023_ICONS = Object.freeze([
|
|
31
|
-
{ src: "/pwa-64x64.png", sizes: "64x64", type: "image/png" },
|
|
32
|
-
{ src: "/pwa-192x192.png", sizes: "192x192", type: "image/png" },
|
|
33
|
-
{ src: "/pwa-512x512.png", sizes: "512x512", type: "image/png" },
|
|
34
|
-
{
|
|
35
|
-
src: "/maskable-icon-512x512.png",
|
|
36
|
-
sizes: "512x512",
|
|
37
|
-
type: "image/png",
|
|
38
|
-
purpose: "maskable"
|
|
39
|
-
}
|
|
40
|
-
].map((icon) => Object.freeze(icon)));
|
|
41
|
-
function webAppManifest(options) {
|
|
42
|
-
return {
|
|
43
|
-
id: options.id ?? "/",
|
|
44
|
-
name: options.name,
|
|
45
|
-
short_name: options.shortName ?? options.name,
|
|
46
|
-
description: options.description,
|
|
47
|
-
lang: options.lang,
|
|
48
|
-
dir: options.dir ?? "ltr",
|
|
49
|
-
start_url: options.startUrl ?? "/",
|
|
50
|
-
scope: options.scope ?? "/",
|
|
51
|
-
display: options.display ?? "standalone",
|
|
52
|
-
theme_color: options.themeColor,
|
|
53
|
-
background_color: options.backgroundColor,
|
|
54
|
-
...options.categories && { categories: [...options.categories] },
|
|
55
|
-
icons: (options.icons ?? MINIMAL_2023_ICONS).map((icon) => ({ ...icon }))
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/pwa/model/caching.ts
|
|
60
|
-
var STATIC_EXTENSION = /\.(?:js|mjs|css|woff2?|ttf|otf|svg|png|jpe?g|webp|avif|gif|ico)$/i;
|
|
61
|
-
var underAssets = (path) => path.startsWith("/assets/");
|
|
62
|
-
function cachingFor(request, origin, options = {}) {
|
|
63
|
-
if (request.method !== "GET")
|
|
64
|
-
return "none";
|
|
65
|
-
if (request.mode === "navigate")
|
|
66
|
-
return "navigation";
|
|
67
|
-
const url = new URL(request.url);
|
|
68
|
-
if (url.origin !== origin)
|
|
69
|
-
return "none";
|
|
70
|
-
if (request.headers.has("authorization"))
|
|
71
|
-
return "none";
|
|
72
|
-
if (url.search)
|
|
73
|
-
return "none";
|
|
74
|
-
const path = url.pathname;
|
|
75
|
-
if (path.endsWith(".data") || path === "/__manifest" || path === (options.serviceWorkerUrl ?? options.contract?.serviceWorkerUrl ?? SERVICE_WORKER_URL2) || path === (options.manifestPath ?? MANIFEST_PATH) || options.never?.(path)) {
|
|
76
|
-
return "none";
|
|
77
|
-
}
|
|
78
|
-
if (request.destination === "document" || request.destination === "iframe")
|
|
79
|
-
return "none";
|
|
80
|
-
if (!STATIC_EXTENSION.test(path))
|
|
81
|
-
return "none";
|
|
82
|
-
return (options.immutable ?? underAssets)(path) ? "immutable" : "static";
|
|
83
|
-
}
|
|
19
|
+
} from "../chunks/index-9xv2a8et.js";
|
|
20
|
+
import {
|
|
21
|
+
parseBrowserManifest2,
|
|
22
|
+
precacheList2,
|
|
23
|
+
assetPrecache2
|
|
24
|
+
} from "../chunks/index-5gqcpyyg.js";
|
|
25
|
+
import {
|
|
26
|
+
SERVICE_WORKER_URL2,
|
|
27
|
+
OFFLINE_URL2,
|
|
28
|
+
SKIP_WAITING2,
|
|
29
|
+
defineWorkerContract2
|
|
30
|
+
} from "../chunks/index-rfr02vg4.js";
|
|
84
31
|
// src/pwa/model/clear-app-caches.ts
|
|
85
32
|
async function clearAppCaches(contract) {
|
|
86
33
|
if (typeof caches === "undefined")
|
|
@@ -88,78 +35,31 @@ async function clearAppCaches(contract) {
|
|
|
88
35
|
const names = contract.clearableCaches(await caches.keys());
|
|
89
36
|
await Promise.all(names.map((name) => caches.delete(name)));
|
|
90
37
|
}
|
|
91
|
-
// src/pwa/model/precache-list.ts
|
|
92
|
-
var HASHED_ASSET = /^\/assets\/[^/]+-[\w-]{8}\.(?:js|css)$/;
|
|
93
|
-
function parseBrowserManifest(source) {
|
|
94
|
-
const start = source.indexOf("{");
|
|
95
|
-
const end = source.lastIndexOf("}");
|
|
96
|
-
if (start < 0 || end < start) {
|
|
97
|
-
throw new Error("parseBrowserManifest(): not React Router's browser manifest (build/client/assets/manifest-*.js).");
|
|
98
|
-
}
|
|
99
|
-
return JSON.parse(source.slice(start, end + 1));
|
|
100
|
-
}
|
|
101
|
-
function precacheList(manifest) {
|
|
102
|
-
const urls = new Set([manifest.url]);
|
|
103
|
-
for (const part of [manifest.entry, ...Object.values(manifest.routes)]) {
|
|
104
|
-
for (const url of [
|
|
105
|
-
...part.module ? [part.module] : [],
|
|
106
|
-
...part.imports ?? [],
|
|
107
|
-
...part.css ?? []
|
|
108
|
-
]) {
|
|
109
|
-
urls.add(url);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return [...urls].filter((url) => HASHED_ASSET.test(url)).map((url) => ({ url, revision: null }));
|
|
113
|
-
}
|
|
114
|
-
function assetPrecache(assetFiles, include, base = "/assets/") {
|
|
115
|
-
return assetFiles.filter((file) => {
|
|
116
|
-
include.lastIndex = 0;
|
|
117
|
-
return include.test(file);
|
|
118
|
-
}).sort().map((file) => ({ url: `${base}${file}`, revision: null }));
|
|
119
|
-
}
|
|
120
|
-
// src/pwa/model/storable.ts
|
|
121
|
-
var STATIC_CONTENT_TYPE = /^(?:(?:text|application)\/(?:javascript|x-javascript|ecmascript)|text\/css|font\/[\w.+-]+|application\/(?:font-woff2?|x-font-[\w.+-]+|vnd\.ms-fontobject)|image\/[\w.+-]+)$/i;
|
|
122
|
-
function isStorable(response) {
|
|
123
|
-
if (response.status !== 200)
|
|
124
|
-
return false;
|
|
125
|
-
if (response.type !== "basic" && response.type !== "default")
|
|
126
|
-
return false;
|
|
127
|
-
const contentType = (response.headers.get("content-type") ?? "").split(";")[0]?.trim();
|
|
128
|
-
if (!contentType || !STATIC_CONTENT_TYPE.test(contentType))
|
|
129
|
-
return false;
|
|
130
|
-
const cacheControl = response.headers.get("cache-control") ?? "";
|
|
131
|
-
if (!/\bpublic\b/i.test(cacheControl))
|
|
132
|
-
return false;
|
|
133
|
-
if (/\b(?:no-store|private)\b/i.test(cacheControl))
|
|
134
|
-
return false;
|
|
135
|
-
const vary = response.headers.get("vary") ?? "";
|
|
136
|
-
return !/(?:^|,)\s*(?:\*|cookie|authorization)\s*(?:,|$)/i.test(vary);
|
|
137
|
-
}
|
|
138
38
|
export {
|
|
139
|
-
MANIFEST_HEADERS,
|
|
140
|
-
MANIFEST_PATH,
|
|
141
|
-
MINIMAL_2023_ICONS,
|
|
39
|
+
MANIFEST_HEADERS2 as MANIFEST_HEADERS,
|
|
40
|
+
MANIFEST_PATH2 as MANIFEST_PATH,
|
|
41
|
+
MINIMAL_2023_ICONS2 as MINIMAL_2023_ICONS,
|
|
142
42
|
OFFLINE_URL2 as OFFLINE_URL,
|
|
143
43
|
SERVICE_WORKER_URL2 as SERVICE_WORKER_URL,
|
|
144
44
|
SKIP_WAITING2 as SKIP_WAITING,
|
|
145
45
|
UPDATE_LATER_KEY2 as UPDATE_LATER_KEY,
|
|
146
46
|
afterLoad2 as afterLoad,
|
|
147
|
-
assetPrecache,
|
|
148
|
-
cachingFor,
|
|
47
|
+
assetPrecache2 as assetPrecache,
|
|
48
|
+
cachingFor2 as cachingFor,
|
|
149
49
|
clearAppCaches,
|
|
150
50
|
createUpdateNotice2 as createUpdateNotice,
|
|
151
51
|
createUpdater2 as createUpdater,
|
|
152
52
|
defineWorkerContract2 as defineWorkerContract,
|
|
153
|
-
isStorable,
|
|
154
|
-
manifestHref,
|
|
155
|
-
manifestLanguage,
|
|
156
|
-
parseBrowserManifest,
|
|
157
|
-
precacheList,
|
|
53
|
+
isStorable2 as isStorable,
|
|
54
|
+
manifestHref2 as manifestHref,
|
|
55
|
+
manifestLanguage2 as manifestLanguage,
|
|
56
|
+
parseBrowserManifest2 as parseBrowserManifest,
|
|
57
|
+
precacheList2 as precacheList,
|
|
158
58
|
registerServiceWorker2 as registerServiceWorker,
|
|
159
59
|
sessionStore2 as sessionStore,
|
|
160
60
|
watchForUpdates2 as watchForUpdates,
|
|
161
|
-
webAppManifest
|
|
61
|
+
webAppManifest2 as webAppManifest
|
|
162
62
|
};
|
|
163
63
|
|
|
164
|
-
//# debugId=
|
|
64
|
+
//# debugId=7B8375F7BF1AB78E64756E2164756E21
|
|
165
65
|
//# sourceMappingURL=index.js.map
|
package/dist/pwa/index.js.map
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/pwa/model/
|
|
3
|
+
"sources": ["../src/pwa/model/clear-app-caches.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"
|
|
6
|
-
"import { MANIFEST_PATH } from './manifest';\nimport { SERVICE_WORKER_URL, type WorkerContract } from './worker-contract';\n\n/**\n * Which requests the service worker caches, and how. Pure, so that what is\n * never cached is tested, not hoped for.\n *\n * - `navigation`: a page load. Always from the network, never stored; the\n * offline page answers only when the network fails.\n * - `immutable`: a hashed bundle: cache-first.\n * - `static`: another same-origin static file (icon, sprite, logo):\n * stale-while-revalidate.\n * - `none`: left to the browser, untouched: every non-GET, any other\n * origin, React Router's `.data` and `/__manifest`, the worker and the\n * manifest themselves, the app's own `never` paths, and anything carrying\n * credentials.\n */\nexport type Caching = 'navigation' | 'immutable' | 'static' | 'none';\n\n/** What a `Request` exposes that the decision reads. */\nexport interface RequestFacts {\n\treadonly method: string;\n\treadonly url: string;\n\treadonly mode: string;\n\treadonly destination: string;\n\treadonly headers: Pick<Headers, 'has'>;\n}\n\nexport interface CachingOptions {\n\t/**\n\t * The worker's own path, never cached. Wins over `contract`;\n\t * `SERVICE_WORKER_URL` when neither is given.\n\t */\n\tserviceWorkerUrl?: string;\n\t/** The app's contract, whose `serviceWorkerUrl` is never cached. */\n\tcontract?: Pick<WorkerContract, 'serviceWorkerUrl'>;\n\t/** The web app manifest's path, never cached. `MANIFEST_PATH` by default. */\n\tmanifestPath?: string;\n\t/** Paths of the app answered fresh every time, such as `(p) => p.startsWith('/api/')`. */\n\tnever?: (path: string) => boolean;\n\t/**\n\t * Which static paths are immutable (cache-first) rather than static.\n\t * `(path) => path.startsWith('/assets/')` by default, as `serveClient`\n\t * serves them.\n\t */\n\timmutable?: (path: string) => boolean;\n}\n\nconst STATIC_EXTENSION =\n\t/\\.(?:js|mjs|css|woff2?|ttf|otf|svg|png|jpe?g|webp|avif|gif|ico)$/i;\n\nconst underAssets = (path: string) => path.startsWith('/assets/');\n\n/** How the worker answers `request`, for an app served at `origin`. */\nexport function cachingFor(\n\trequest: RequestFacts,\n\torigin: string,\n\toptions: CachingOptions = {},\n): Caching {\n\tif (request.method !== 'GET') return 'none';\n\tif (request.mode === 'navigate') return 'navigation';\n\tconst url = new URL(request.url);\n\tif (url.origin !== origin) return 'none';\n\tif (request.headers.has('authorization')) return 'none';\n\tif (url.search) return 'none';\n\tconst path = url.pathname;\n\tif (\n\t\tpath.endsWith('.data') || // React Router single fetch: loader data\n\t\tpath === '/__manifest' || // React Router route discovery\n\t\tpath ===\n\t\t\t(options.serviceWorkerUrl ??\n\t\t\t\toptions.contract?.serviceWorkerUrl ??\n\t\t\t\tSERVICE_WORKER_URL) ||\n\t\tpath === (options.manifestPath ?? MANIFEST_PATH) ||\n\t\toptions.never?.(path)\n\t) {\n\t\treturn 'none';\n\t}\n\tif (request.destination === 'document' || request.destination === 'iframe')\n\t\treturn 'none';\n\tif (!STATIC_EXTENSION.test(path)) return 'none';\n\treturn (options.immutable ?? underAssets)(path) ? 'immutable' : 'static';\n}\n",
|
|
7
|
-
"import type { WorkerContract } from './worker-contract';\n\n/**\n * Deletes every cache the service worker filled, but the offline page.\n * For sign-out: what the caches hold is static and public by design, and\n * clearing them leaves nothing behind anyway. Safe where Cache Storage does\n * not exist (server, old browsers).\n */\nexport async function clearAppCaches(\n\tcontract: Pick<WorkerContract, 'clearableCaches'>,\n): Promise<void> {\n\tif (typeof caches === 'undefined') return;\n\tconst names = contract.clearableCaches(await caches.keys());\n\tawait Promise.all(names.map((name) => caches.delete(name)));\n}\n",
|
|
8
|
-
"/**\n * What the service worker precaches, read from a build: every script and\n * stylesheet React Router's manifest names (the client entry and each\n * route's module, imports and CSS), and the manifest itself, so a client\n * navigation offline to a route never visited still finds its code. Only\n * hashed `/assets/` files: a new build names new files, so each precaches\n * under its own URL, revision `null`. Chunks only a component loads on\n * demand stay out: a cache-first route stores them the first time they load.\n *\n * Dependency-free: a build script runs it at build time.\n */\n\n/** A route or the entry, as `window.__reactRouterManifest` lists it. */\ntype ManifestModule = { module?: string; imports?: string[]; css?: string[] };\n\n/** The parts of React Router's browser manifest the list reads. */\nexport type BrowserManifest = {\n\turl: string;\n\tentry: ManifestModule;\n\troutes: Record<string, ManifestModule>;\n};\n\n/** A Workbox precache entry: a hashed URL needs no revision. */\nexport type PrecacheEntry = { url: string; revision: string | null };\n\n/** A Vite-hashed file under `/assets/`: `name-<8 hash chars>.js|css`. */\nconst HASHED_ASSET = /^\\/assets\\/[^/]+-[\\w-]{8}\\.(?:js|css)$/;\n\n/** Reads `window.__reactRouterManifest={…};` (build/client/assets/manifest-*.js). */\nexport function parseBrowserManifest(source: string): BrowserManifest {\n\tconst start = source.indexOf('{');\n\tconst end = source.lastIndexOf('}');\n\tif (start < 0 || end < start) {\n\t\tthrow new Error(\n\t\t\t\"parseBrowserManifest(): not React Router's browser manifest (build/client/assets/manifest-*.js).\",\n\t\t);\n\t}\n\treturn JSON.parse(source.slice(start, end + 1)) as BrowserManifest;\n}\n\n/** The hashed scripts and stylesheets every route needs, the manifest's own file first. */\nexport function precacheList(manifest: BrowserManifest): PrecacheEntry[] {\n\tconst urls = new Set<string>([manifest.url]);\n\tfor (const part of [manifest.entry, ...Object.values(manifest.routes)]) {\n\t\tfor (const url of [\n\t\t\t...(part.module ? [part.module] : []),\n\t\t\t...(part.imports ?? []),\n\t\t\t...(part.css ?? []),\n\t\t]) {\n\t\t\turls.add(url);\n\t\t}\n\t}\n\treturn [...urls]\n\t\t.filter((url) => HASHED_ASSET.test(url))\n\t\t.map((url) => ({ url, revision: null }));\n}\n\n/**\n * The precache entries of the files among `assetFiles` (the names in\n * build/client/assets) that `include` matches, sorted, under `base`: fonts\n * an app keeps offline, say. The regex is the app's.\n */\nexport function assetPrecache(\n\tassetFiles: readonly string[],\n\tinclude: RegExp,\n\tbase = '/assets/',\n): PrecacheEntry[] {\n\treturn assetFiles\n\t\t.filter((file) => {\n\t\t\tinclude.lastIndex = 0; // a /g or /y regex remembers its last match\n\t\t\treturn include.test(file);\n\t\t})\n\t\t.sort()\n\t\t.map((file) => ({ url: `${base}${file}`, revision: null }));\n}\n",
|
|
9
|
-
"/**\n * The content types of the static extensions: scripts, styles, fonts and\n * images (SVG and icons included). A page, JSON or anything else served\n * under a static-looking path is refused all the same.\n */\nconst STATIC_CONTENT_TYPE =\n\t/^(?:(?:text|application)\\/(?:javascript|x-javascript|ecmascript)|text\\/css|font\\/[\\w.+-]+|application\\/(?:font-woff2?|x-font-[\\w.+-]+|vnd\\.ms-fontobject)|image\\/[\\w.+-]+)$/i;\n\n/**\n * Whether a response may be stored: a full, same-origin 200 of a static\n * content type, that the server marked `public` (alxia does on every\n * static file it serves; a route answering an image, a user's photo, does\n * not), not private nor no-store, and that does not vary on who asks.\n */\nexport function isStorable(response: Response): boolean {\n\tif (response.status !== 200) return false;\n\tif (response.type !== 'basic' && response.type !== 'default') return false;\n\tconst contentType = (response.headers.get('content-type') ?? '')\n\t\t.split(';')[0]\n\t\t?.trim();\n\tif (!contentType || !STATIC_CONTENT_TYPE.test(contentType)) return false;\n\tconst cacheControl = response.headers.get('cache-control') ?? '';\n\tif (!/\\bpublic\\b/i.test(cacheControl)) return false;\n\tif (/\\b(?:no-store|private)\\b/i.test(cacheControl)) return false;\n\tconst vary = response.headers.get('vary') ?? '';\n\treturn !/(?:^|,)\\s*(?:\\*|cookie|authorization)\\s*(?:,|$)/i.test(vary);\n}\n"
|
|
5
|
+
"import type { WorkerContract } from './worker-contract';\n\n/**\n * Deletes every cache the service worker filled, but the offline page.\n * For sign-out: what the caches hold is static and public by design, and\n * clearing them leaves nothing behind anyway. Safe where Cache Storage does\n * not exist (server, old browsers).\n */\nexport async function clearAppCaches(\n\tcontract: Pick<WorkerContract, 'clearableCaches'>,\n): Promise<void> {\n\tif (typeof caches === 'undefined') return;\n\tconst names = contract.clearableCaches(await caches.keys());\n\tawait Promise.all(names.map((name) => caches.delete(name)));\n}\n"
|
|
10
6
|
],
|
|
11
|
-
"mappings": "
|
|
12
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,eAAsB,cAAc,CACnC,UACgB;AAAA,EAChB,IAAI,OAAO,WAAW;AAAA,IAAa;AAAA,EACnC,MAAM,QAAQ,SAAS,gBAAgB,MAAM,OAAO,KAAK,CAAC;AAAA,EAC1D,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAS,OAAO,OAAO,IAAI,CAAC,CAAC;AAAA;",
|
|
8
|
+
"debugId": "7B8375F7BF1AB78E64756E2164756E21",
|
|
13
9
|
"names": []
|
|
14
10
|
}
|
package/dist/pwa/react/index.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@alxia/react-router/pwa/worker`: the service worker on Workbox. Import it
|
|
3
|
+
* from a service worker bundle alone, never from a page. The six `workbox-*`
|
|
4
|
+
* packages (`core`, `expiration`, `navigation-preload`, `precaching`,
|
|
5
|
+
* `routing`, `strategies`, optional peers) are its only package imports.
|
|
6
|
+
*/
|
|
7
|
+
export type { ExpirationOptions, WorkerOptions } from './plan';
|
|
8
|
+
export { startWorker } from './start-worker';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pwa/worker/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|