@sovereignbase/pwa 0.0.2 → 1.0.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/LICENSE +200 -200
- package/README.md +180 -0
- package/dist/{htmlDocument-Cx-dprM5.cjs → htmlDocument-C3k13Sjr.cjs} +3 -10
- package/dist/htmlDocument-C3k13Sjr.cjs.map +1 -0
- package/dist/{htmlDocument-DABSNDvf.js → htmlDocument-C533Sj5O.js} +3 -10
- package/dist/htmlDocument-C533Sj5O.js.map +1 -0
- package/dist/index.cjs +264 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -109
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +60 -109
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -41
- package/dist/index.js.map +1 -1
- package/dist/serviceWorker/entrypoint.cjs +19 -13
- package/dist/serviceWorker/entrypoint.cjs.map +1 -1
- package/dist/serviceWorker/entrypoint.js +19 -13
- package/dist/serviceWorker/entrypoint.js.map +1 -1
- package/package.json +1 -1
- package/dist/htmlDocument-Cx-dprM5.cjs.map +0 -1
- package/dist/htmlDocument-DABSNDvf.js.map +0 -1
|
@@ -14,13 +14,6 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { Bytes } from "@sovereignbase/bytecodec";
|
|
18
|
-
//#region src/cspHash/index.ts
|
|
19
|
-
const cspHash = async (source) => {
|
|
20
|
-
const digest = await crypto.subtle.digest("SHA-256", Bytes.fromString(source));
|
|
21
|
-
return `sha256-${Bytes.toBase64String(digest)}`;
|
|
22
|
-
};
|
|
23
|
-
//#endregion
|
|
24
17
|
//#region src/seoComponents/jsonldMarkup.ts
|
|
25
18
|
/**
|
|
26
19
|
* Generates Schema.org JSON-LD markup describing a website,
|
|
@@ -202,14 +195,14 @@ const documentMarkup = async ({ language, title, applicationName, themeColor, bo
|
|
|
202
195
|
|
|
203
196
|
${headMarkup}
|
|
204
197
|
|
|
205
|
-
${stylesheet ? `<style
|
|
198
|
+
${stylesheet ? `<style>
|
|
206
199
|
${stylesheet}
|
|
207
200
|
</style>` : ""}
|
|
208
201
|
|
|
209
202
|
</head>
|
|
210
203
|
<body>
|
|
211
204
|
${bodyMarkup}
|
|
212
|
-
${entrypoint ? `<script type="module"
|
|
205
|
+
${entrypoint ? `<script type="module">
|
|
213
206
|
${entrypoint}
|
|
214
207
|
<\/script>` : ""}
|
|
215
208
|
</body>
|
|
@@ -217,4 +210,4 @@ ${entrypoint}
|
|
|
217
210
|
//#endregion
|
|
218
211
|
export { documentMarkup as t };
|
|
219
212
|
|
|
220
|
-
//# sourceMappingURL=htmlDocument-
|
|
213
|
+
//# sourceMappingURL=htmlDocument-C533Sj5O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlDocument-C533Sj5O.js","names":["seo.jsonLDMarkup","seo.languageLinksMarkup","seo.ogMarkup","seo.twitterMarkup"],"sources":["../src/seoComponents/jsonldMarkup.ts","../src/seoComponents/languageLinksMarkup.ts","../src/seoComponents/ogMarkup.ts","../src/seoComponents/twitterMarkup.ts","../src/htmlDocument/index.ts"],"sourcesContent":["import type { JSONLDMarkup } from '../.types/index.js'\n\n/**\n * Generates Schema.org JSON-LD markup describing a website,\n * its web application, the current localized page, and publisher.\n */\nexport const jsonLDMarkup = ({\n site,\n application,\n page,\n organization,\n}: JSONLDMarkup) => {\n const siteId = `${site.url}#website`\n const applicationId = `${application.url}#application`\n const organizationId = `${organization.url}#organization`\n const pageId = `${page.url}#webpage`\n\n const data = {\n '@context': 'https://schema.org',\n '@graph': [\n {\n '@type': 'WebSite',\n '@id': siteId,\n name: site.name,\n url: site.url,\n publisher: {\n '@id': organizationId,\n },\n },\n\n {\n '@type': 'WebApplication',\n '@id': applicationId,\n name: application.name,\n url: application.url,\n inLanguage: application.inLanguage,\n\n ...(application.applicationCategory\n ? { applicationCategory: application.applicationCategory }\n : {}),\n\n ...(application.operatingSystem\n ? { operatingSystem: application.operatingSystem }\n : {}),\n\n ...(application.browserRequirements\n ? { browserRequirements: application.browserRequirements }\n : {}),\n\n ...(application.featureList\n ? { featureList: application.featureList }\n : {}),\n\n ...(application.screenshot\n ? { screenshot: application.screenshot }\n : {}),\n\n publisher: {\n '@id': organizationId,\n },\n },\n\n {\n '@type': 'WebPage',\n '@id': pageId,\n name: page.name,\n description: page.description,\n url: page.url,\n inLanguage: page.inLanguage,\n\n isPartOf: {\n '@id': siteId,\n },\n\n mainEntity: {\n '@id': applicationId,\n },\n },\n\n {\n '@type': 'Organization',\n '@id': organizationId,\n name: organization.name,\n url: organization.url,\n logo: {\n '@type': 'ImageObject',\n url: organization.logo,\n },\n },\n ],\n }\n\n return `\n <script type=\"application/ld+json\">\n${JSON.stringify(data).replaceAll('<', '\\\\u003c')}\n </script>\n`\n}\n","import type { BCP47LanguageTag } from '@sovereignbase/utils'\n\n/**\n * Generates canonical and language-alternate link markup for a localized page.\n *\n * Produces:\n * - a canonical link for the current language,\n * - `hreflang` alternate links for each supported alternate language,\n * - an `x-default` alternate link for the default language.\n *\n * @param host Registrable domain, such as `example.com` or `example.co.uk`.\n * @param defaultLanguage Language used for the `x-default` URL.\n * @param canonicalLanguage Language used for the canonical URL.\n * @param alternateLanguages Languages exposed through `hreflang` alternate links.\n * @param pathSuffix Optional path suffix starting with `/`.\n */\nexport const languageLinksMarkup = (\n host: `${string /* domain */}.${string /* public suffix */}`,\n defaultLanguage: BCP47LanguageTag,\n canonicalLanguage: BCP47LanguageTag,\n alternateLanguages: BCP47LanguageTag[],\n pathSuffix: '' | `/${string}` = ''\n) => `\n <link rel=\"canonical\" href=\"https://${host}/${canonicalLanguage}${pathSuffix}\" />\n ${(() => {\n let markup = ``\n for (const language of alternateLanguages)\n markup += ` <link rel=\"alternate\" hreflang=\"${language}\" href=\"https://${host}/${language}${pathSuffix}\" />`\n return markup\n })()}\n <link rel=\"alternate\" hreflang=\"x-default\" href=\"https://${host}/${defaultLanguage}${pathSuffix}\" />\n`\n","import type { OpenGraphLocale } from '@sovereignbase/utils'\n\n/**\n * Generates Open Graph metadata markup.\n *\n * @param locale Open Graph locale, such as `fi_FI` or `en_US`.\n * @param siteName Site or application name.\n * @param title Page title.\n * @param description Page description.\n * @param url Canonical URL of the page.\n * @param imageUrl URL of the social sharing image.\n * @param imageAlt Alternative text for the social sharing image.\n * @param imageWidth Width of the social sharing image in pixels.\n * @param imageHeight Height of the social sharing image in pixels.\n */\nexport const ogMarkup = (\n locale: OpenGraphLocale,\n siteName: string,\n title: string,\n description: string,\n url: `https://${string}`,\n imageUrl: string,\n imageAlt: string,\n imageWidth: number = 1200,\n imageHeight: number = 630\n) => `\n <meta property=\"og:locale\" content=\"${locale}\" />\n <meta property=\"og:type\" content=\"website\" />\n <meta property=\"og:site_name\" content=\"${siteName}\" />\n <meta property=\"og:title\" content=\"${title}\" />\n <meta property=\"og:description\" content=\"${description}\" />\n <meta property=\"og:url\" content=\"${url}\" />\n <meta property=\"og:image\" content=\"${imageUrl}\" />\n <meta property=\"og:image:width\" content=\"${imageWidth}\" />\n <meta property=\"og:image:height\" content=\"${imageHeight}\" />\n <meta property=\"og:image:alt\" content=\"${imageAlt}\" />\n`\n","/**\n * Generates Twitter Card metadata markup.\n *\n * @param title Page title.\n * @param description Page description.\n * @param url Canonical URL of the page.\n * @param imageUrl URL of the social sharing image.\n * @param imageAlt Alternative text for the social sharing image.\n * @param site Twitter/X handle of the site.\n * @param creator Twitter/X handle of the content creator.\n */\nexport const twitterMarkup = (\n title: string,\n description: string,\n url: `https://${string}`,\n imageUrl: string,\n imageAlt: string,\n site: `@${string}`,\n creator: `@${string}`\n) => `\n <meta name=\"twitter:card\" content=\"summary_large_image\" />\n <meta name=\"twitter:title\" content=\"${title}\" />\n <meta name=\"twitter:description\" content=\"${description}\" />\n <meta name=\"twitter:url\" content=\"${url}\" />\n <meta name=\"twitter:image\" content=\"${imageUrl}\" />\n <meta name=\"twitter:image:alt\" content=\"${imageAlt}\" />\n <meta name=\"twitter:site\" content=\"${site}\" />\n <meta name=\"twitter:creator\" content=\"${creator}\" />\n`\n","import { DocumentMarkupOptions } from '../.types/index.js'\nimport * as seo from '../seoComponents/index.js'\n/**\n * Generates a complete HTML document for a web application.\n *\n * Supports:\n * - localized document language,\n * - application and theme metadata,\n * - Web App Manifest integration,\n * - favicon and Apple/Safari application icons,\n * - critical inline styles,\n * - inline ES module initialization,\n * - arbitrary additional head markup.\n */\nexport const documentMarkup = async ({\n language,\n title,\n applicationName,\n themeColor,\n bodyMarkup = '',\n headMarkup = '',\n stylesheet = '',\n entrypoint = '',\n iconUrl,\n appleTouchIconUrl,\n maskIconUrl,\n manifestUrl,\n maskIconColor = themeColor,\n colorScheme = 'light dark',\n appleStatusBarStyle = 'black-translucent',\n seo: documentSEO,\n}: DocumentMarkupOptions): Promise<string> =>\n `<!DOCTYPE html>\n<html lang=\"${language}\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>${title}</title>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n\n <meta name=\"application-name\" content=\"${applicationName}\" />\n <meta name=\"color-scheme\" content=\"${colorScheme}\" />\n <meta name=\"theme-color\" content=\"${themeColor}\" />\n\n <meta name=\"mobile-web-app-capable\" content=\"yes\" />\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n <meta name=\"apple-mobile-web-app-title\" content=\"${applicationName}\" />\n <meta\n name=\"apple-mobile-web-app-status-bar-style\"\n content=\"${appleStatusBarStyle}\"\n />\n\n ${iconUrl ? `<link rel=\"icon\" href=\"${iconUrl}\" />` : ''}\n ${\n appleTouchIconUrl\n ? `<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"${appleTouchIconUrl}\" />`\n : ''\n }\n ${\n maskIconUrl\n ? `<link rel=\"mask-icon\" href=\"${maskIconUrl}\" color=\"${maskIconColor}\" />`\n : ''\n }\n ${manifestUrl ? `<link rel=\"manifest\" href=\"${manifestUrl}\" />` : ''}\n\n ${seo.jsonLDMarkup(documentSEO.jsonLD)}\n ${seo.languageLinksMarkup(\n documentSEO.languageLinks.host,\n documentSEO.languageLinks.defaultLanguage,\n documentSEO.languageLinks.canonicalLanguage,\n documentSEO.languageLinks.alternateLanguages,\n documentSEO.languageLinks.pathSuffix\n )}\n ${seo.ogMarkup(\n documentSEO.openGraph.locale,\n documentSEO.openGraph.siteName,\n documentSEO.openGraph.title,\n documentSEO.openGraph.description,\n documentSEO.openGraph.url,\n documentSEO.openGraph.imageUrl,\n documentSEO.openGraph.imageAlt,\n documentSEO.openGraph.imageWidth,\n documentSEO.openGraph.imageHeight\n )}\n ${seo.twitterMarkup(\n documentSEO.twitter.title,\n documentSEO.twitter.description,\n documentSEO.twitter.url,\n documentSEO.twitter.imageUrl,\n documentSEO.twitter.imageAlt,\n documentSEO.twitter.site,\n documentSEO.twitter.creator\n )}\n\n ${headMarkup}\n\n ${\n stylesheet\n ? `<style>\n${stylesheet}\n </style>`\n : ''\n }\n\n </head>\n <body>\n${bodyMarkup}\n${\n entrypoint\n ? `<script type=\"module\">\n${entrypoint}\n </script>`\n : ''\n}\n </body>\n</html>`\n .replace(/>\\s+</g, '><')\n .trim()\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -15,16 +15,25 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
18
|
-
const require_htmlDocument = require("./htmlDocument-
|
|
18
|
+
const require_htmlDocument = require("./htmlDocument-C3k13Sjr.cjs");
|
|
19
|
+
let node_crypto = require("node:crypto");
|
|
19
20
|
let node_fs = require("node:fs");
|
|
20
21
|
let node_fs_promises = require("node:fs/promises");
|
|
21
22
|
let node_path = require("node:path");
|
|
23
|
+
let _sovereignbase_bytecodec = require("@sovereignbase/bytecodec");
|
|
22
24
|
let esbuild = require("esbuild");
|
|
23
25
|
let lightningcss = require("lightningcss");
|
|
24
26
|
let html_minifier_terser = require("html-minifier-terser");
|
|
25
27
|
let node_url = require("node:url");
|
|
26
28
|
let terser = require("terser");
|
|
29
|
+
//#region src/cspHash/index.ts
|
|
30
|
+
const cspHash = async (source) => {
|
|
31
|
+
const digest = await crypto.subtle.digest("SHA-256", _sovereignbase_bytecodec.Bytes.fromString(source));
|
|
32
|
+
return `sha256-${_sovereignbase_bytecodec.Bytes.toBase64String(digest)}`;
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
27
35
|
//#region src/minifyCss/index.ts
|
|
36
|
+
const minifiedOutputs$2 = /* @__PURE__ */ new Map();
|
|
28
37
|
/** Bundles and minifies a CSS entrypoint into a dense string. */
|
|
29
38
|
async function minifyCss(entrypoint) {
|
|
30
39
|
const bundled = await (0, esbuild.build)({
|
|
@@ -36,18 +45,26 @@ async function minifyCss(entrypoint) {
|
|
|
36
45
|
write: false,
|
|
37
46
|
external: ["/assets/*"]
|
|
38
47
|
});
|
|
48
|
+
const source = bundled.outputFiles[0].text;
|
|
49
|
+
const cached = minifiedOutputs$2.get(source);
|
|
50
|
+
if (cached !== void 0) return cached;
|
|
39
51
|
const { code } = (0, lightningcss.transform)({
|
|
40
52
|
code: bundled.outputFiles[0].contents,
|
|
41
53
|
filename: entrypoint.toString(),
|
|
42
54
|
minify: true
|
|
43
55
|
});
|
|
44
|
-
|
|
56
|
+
const output = new TextDecoder().decode(code).trim();
|
|
57
|
+
minifiedOutputs$2.set(source, output);
|
|
58
|
+
return output;
|
|
45
59
|
}
|
|
46
60
|
//#endregion
|
|
47
61
|
//#region src/minifyHtml/index.ts
|
|
62
|
+
const minifiedOutputs$1 = /* @__PURE__ */ new Map();
|
|
48
63
|
/** Minifies a complete HTML document, including inline CSS and JavaScript. */
|
|
49
64
|
async function minifyHtml(source) {
|
|
50
|
-
|
|
65
|
+
const cached = minifiedOutputs$1.get(source);
|
|
66
|
+
if (cached !== void 0) return cached;
|
|
67
|
+
const output = await (0, html_minifier_terser.minify)(source, {
|
|
51
68
|
collapseBooleanAttributes: true,
|
|
52
69
|
collapseInlineTagWhitespace: true,
|
|
53
70
|
collapseWhitespace: true,
|
|
@@ -73,17 +90,21 @@ async function minifyHtml(source) {
|
|
|
73
90
|
sortClassName: true,
|
|
74
91
|
useShortDoctype: true
|
|
75
92
|
});
|
|
93
|
+
minifiedOutputs$1.set(source, output);
|
|
94
|
+
return output;
|
|
76
95
|
}
|
|
77
96
|
//#endregion
|
|
78
97
|
//#region src/minifyJs/index.ts
|
|
98
|
+
const minifiedOutputs = /* @__PURE__ */ new Map();
|
|
79
99
|
/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */
|
|
80
|
-
async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
81
|
-
|
|
100
|
+
async function minifyJs(input, { banner, define, passes = 3 } = {}) {
|
|
101
|
+
const output = (await (0, esbuild.build)({
|
|
82
102
|
...typeof input === "object" && "source" in input ? { stdin: {
|
|
83
103
|
contents: input.source,
|
|
84
104
|
resolveDir: process.cwd()
|
|
85
105
|
} } : { entryPoints: [input instanceof URL ? (0, node_url.fileURLToPath)(input) : input.toString()] },
|
|
86
106
|
bundle: true,
|
|
107
|
+
banner: banner === void 0 ? void 0 : { js: banner },
|
|
87
108
|
define,
|
|
88
109
|
format: "esm",
|
|
89
110
|
legalComments: "none",
|
|
@@ -92,6 +113,15 @@ async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
|
92
113
|
treeShaking: true,
|
|
93
114
|
write: false
|
|
94
115
|
})).outputFiles[0].text;
|
|
116
|
+
const cacheKey = `${passes}\0${output}`;
|
|
117
|
+
const cached = minifiedOutputs.get(cacheKey);
|
|
118
|
+
if (cached !== void 0) return cached;
|
|
119
|
+
const result = await repeatedlyMinify(output, passes);
|
|
120
|
+
minifiedOutputs.set(cacheKey, result);
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
async function repeatedlyMinify(source, passes) {
|
|
124
|
+
let output = source;
|
|
95
125
|
for (let round = 0; round < passes; round += 1) {
|
|
96
126
|
const result = await (0, terser.minify)(output, {
|
|
97
127
|
compress: {
|
|
@@ -109,6 +139,7 @@ async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
|
109
139
|
module: true,
|
|
110
140
|
toplevel: true
|
|
111
141
|
});
|
|
142
|
+
/* v8 ignore next 3 -- Terser returns code or rejects for this input form. */
|
|
112
143
|
if (result.code === void 0) throw new Error("Terser did not produce JavaScript output");
|
|
113
144
|
output = result.code;
|
|
114
145
|
}
|
|
@@ -159,67 +190,149 @@ const webManifest = ({ name, shortName, description, startUrl, themeColor, icon1
|
|
|
159
190
|
//#region src/index.ts
|
|
160
191
|
async function pwaize(config) {
|
|
161
192
|
const outputDirectory = (0, node_path.join)(config.outDir.toString(), "web");
|
|
162
|
-
const
|
|
193
|
+
const languages = [.../* @__PURE__ */ new Set([config.defaultLanguage, ...config.alternateLanguages])];
|
|
163
194
|
const minifyPasses = config.minifyPasses ?? 3;
|
|
195
|
+
const buildIdUrl = "/@sovereignbase/pwa/pwaize-build-id.txt";
|
|
164
196
|
const serviceWorkerPath = "/ServiceWorker";
|
|
165
197
|
await (0, node_fs_promises.mkdir)(outputDirectory, { recursive: true });
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const sourceDirectory = directory.toString();
|
|
198
|
+
if (config.assetsDir !== void 0) {
|
|
199
|
+
const sourceDirectory = config.assetsDir.toString();
|
|
169
200
|
await (0, node_fs_promises.cp)(sourceDirectory, (0, node_path.join)(outputDirectory, (0, node_path.basename)(sourceDirectory)), { recursive: true });
|
|
170
201
|
}
|
|
202
|
+
if (config.i18nDir !== void 0) {
|
|
203
|
+
const sourceDirectory = config.i18nDir.toString();
|
|
204
|
+
await buildScriptDirectory(sourceDirectory, (0, node_path.join)(outputDirectory, (0, node_path.basename)(sourceDirectory)), minifyPasses);
|
|
205
|
+
}
|
|
171
206
|
const stylesheet = await minifyCss(config.stylesheet);
|
|
172
207
|
const entrypoint = await minifyJs(config.entrypoint, { passes: minifyPasses });
|
|
173
|
-
const installer = await minifyJs({ source: `
|
|
174
|
-
const
|
|
208
|
+
const installer = await minifyJs({ source: `await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:"/",type:"module"});await navigator.serviceWorker.ready;location.reload();` }, { passes: minifyPasses });
|
|
209
|
+
const documentOptions = {};
|
|
210
|
+
const contentSecurityPolicies = {};
|
|
211
|
+
const installerDocuments = [];
|
|
175
212
|
for (const language of languages) {
|
|
176
|
-
const localized = config
|
|
177
|
-
if (localized === void 0) throw new Error(`Missing PWA configuration for language "${language}"`);
|
|
213
|
+
const localized = localizeConfig(config, language, languages);
|
|
178
214
|
const languageDirectory = (0, node_path.join)(outputDirectory, language);
|
|
179
215
|
const manifestPath = `/${language}/manifest.webmanifest`;
|
|
180
|
-
const manifest = webManifest(
|
|
181
|
-
|
|
182
|
-
lang: language
|
|
183
|
-
});
|
|
216
|
+
const manifest = webManifest(localized.manifest);
|
|
217
|
+
documentOptions[language] = localized.document;
|
|
184
218
|
await (0, node_fs_promises.mkdir)(languageDirectory, { recursive: true });
|
|
185
219
|
await (0, node_fs_promises.writeFile)((0, node_path.join)(languageDirectory, "manifest.webmanifest"), manifest);
|
|
186
220
|
const installerDocument = await minifyHtml(await require_htmlDocument.documentMarkup({
|
|
187
221
|
...localized.document,
|
|
188
|
-
language,
|
|
189
|
-
stylesheet: "",
|
|
190
222
|
entrypoint: installer,
|
|
223
|
+
language,
|
|
191
224
|
manifestUrl: manifestPath
|
|
192
225
|
}));
|
|
226
|
+
contentSecurityPolicies[language] = await contentSecurityPolicy([await require_htmlDocument.documentMarkup({
|
|
227
|
+
...localized.document,
|
|
228
|
+
entrypoint,
|
|
229
|
+
language,
|
|
230
|
+
manifestUrl: manifestPath,
|
|
231
|
+
stylesheet
|
|
232
|
+
})]);
|
|
233
|
+
installerDocuments.push(installerDocument);
|
|
193
234
|
await (0, node_fs_promises.writeFile)((0, node_path.join)(languageDirectory, "index.html"), installerDocument);
|
|
194
235
|
if (language === config.defaultLanguage) {
|
|
195
236
|
await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDirectory, "index.html"), installerDocument);
|
|
196
237
|
await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDirectory, "manifest.webmanifest"), manifest);
|
|
197
238
|
}
|
|
198
239
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
240
|
+
if (config._headersFile === true) {
|
|
241
|
+
const installerContentSecurityPolicy = await contentSecurityPolicy(installerDocuments);
|
|
242
|
+
const assetsHeaders = config.assetsDir === void 0 ? "" : `/${(0, node_path.basename)(config.assetsDir.toString())}/*\n Cache-Control: public, max-age=31536000, immutable\n\n`;
|
|
243
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDirectory, "_headers"), `/${serviceWorkerPath.slice(1)}\n Cache-Control: no-cache\n Content-Type: text/javascript;charset=UTF-8\n\n${buildIdUrl}\n Cache-Control: no-cache, no-store, must-revalidate\n Content-Type: text/plain;charset=UTF-8\n\n${assetsHeaders}/*\n Content-Security-Policy: ${installerContentSecurityPolicy}\n X-Content-Type-Options: nosniff\n`);
|
|
244
|
+
}
|
|
245
|
+
const generatedFiles = (await publicFiles(outputDirectory)).filter((url) => url !== serviceWorkerPath && url !== buildIdUrl);
|
|
246
|
+
const precache = [.../* @__PURE__ */ new Set([...generatedFiles, ...config.serviceWorker?.precache ?? []])].sort();
|
|
247
|
+
const staticRoutes = [...new Set(precache.map((url) => new URL(url, "https://pwaize.invalid").pathname).filter((url) => !url.endsWith("/index.html") && url !== "/index.html"))].sort();
|
|
204
248
|
const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule);
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
stylesheet: JSON.stringify(stylesheet)
|
|
218
|
-
},
|
|
219
|
-
passes: minifyPasses
|
|
249
|
+
const initialize = config.serviceWorker?.initialize === void 0 ? "undefined" : functionExpression(config.serviceWorker.initialize);
|
|
250
|
+
const waitUntil = config.serviceWorker?.waitUntil === void 0 ? "undefined" : functionExpression(config.serviceWorker.waitUntil);
|
|
251
|
+
const buildId = await contentBuildId(outputDirectory, generatedFiles, {
|
|
252
|
+
bypassRules,
|
|
253
|
+
contentSecurityPolicies,
|
|
254
|
+
documentOptions,
|
|
255
|
+
entrypoint,
|
|
256
|
+
initialize,
|
|
257
|
+
precache,
|
|
258
|
+
staticRoutes,
|
|
259
|
+
stylesheet,
|
|
260
|
+
waitUntil
|
|
220
261
|
});
|
|
262
|
+
const buildIdDirectory = (0, node_path.join)(outputDirectory, "@sovereignbase", "pwa");
|
|
263
|
+
await (0, node_fs_promises.mkdir)(buildIdDirectory, { recursive: true });
|
|
264
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(buildIdDirectory, "pwaize-build-id.txt"), buildId);
|
|
265
|
+
const compiledServiceWorker = new URL("./serviceWorker/entrypoint.js", require("url").pathToFileURL(__filename).href);
|
|
266
|
+
const serviceWorker = await minifyJs(
|
|
267
|
+
/* v8 ignore next -- the packaged .js path is exercised by runtime tests */
|
|
268
|
+
(0, node_fs.existsSync)(compiledServiceWorker) ? compiledServiceWorker : new URL("./serviceWorker/entrypoint.ts", require("url").pathToFileURL(__filename).href),
|
|
269
|
+
{
|
|
270
|
+
banner: `const __pwaInitialize=${initialize},__pwaWaitUntil=${waitUntil};`,
|
|
271
|
+
define: {
|
|
272
|
+
buildId: JSON.stringify(buildId),
|
|
273
|
+
buildIdUrl: JSON.stringify(buildIdUrl),
|
|
274
|
+
bypassRules: JSON.stringify(bypassRules),
|
|
275
|
+
customInitialize: "__pwaInitialize",
|
|
276
|
+
customWaitUntil: "__pwaWaitUntil",
|
|
277
|
+
defaultLanguage: JSON.stringify(config.defaultLanguage),
|
|
278
|
+
contentSecurityPolicies: JSON.stringify(contentSecurityPolicies),
|
|
279
|
+
documentOptions: JSON.stringify(documentOptions),
|
|
280
|
+
entrypoint: JSON.stringify(entrypoint),
|
|
281
|
+
precache: JSON.stringify(precache),
|
|
282
|
+
staticRoutes: JSON.stringify(staticRoutes),
|
|
283
|
+
stylesheet: JSON.stringify(stylesheet)
|
|
284
|
+
},
|
|
285
|
+
passes: minifyPasses
|
|
286
|
+
}
|
|
287
|
+
);
|
|
221
288
|
await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDirectory, serviceWorkerPath.slice(1)), serviceWorker);
|
|
222
289
|
}
|
|
290
|
+
async function contentSecurityPolicy(documents) {
|
|
291
|
+
const inlineScripts = documents.flatMap((document) => [...document.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script>/gi)].map((match) => match[1]));
|
|
292
|
+
const inlineStyles = documents.flatMap((document) => [...document.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style>/gi)].map((match) => match[1]));
|
|
293
|
+
const hashes = async (sources) => (await Promise.all([...new Set(sources.length === 0 ? [""] : sources)].map(cspHash))).map((hash) => `'${hash}'`).join(" ");
|
|
294
|
+
return [
|
|
295
|
+
`default-src 'self'`,
|
|
296
|
+
`base-uri 'self'`,
|
|
297
|
+
`connect-src 'self' https: wss:`,
|
|
298
|
+
`font-src 'self' data:`,
|
|
299
|
+
`form-action 'self'`,
|
|
300
|
+
`frame-ancestors 'none'`,
|
|
301
|
+
`img-src 'self' data: https:`,
|
|
302
|
+
`manifest-src 'self'`,
|
|
303
|
+
`media-src 'self' data: blob: https:`,
|
|
304
|
+
`object-src 'none'`,
|
|
305
|
+
`script-src 'self' 'unsafe-inline' ${await hashes(inlineScripts)}`,
|
|
306
|
+
`style-src 'self' 'unsafe-inline' ${await hashes(inlineStyles)}`,
|
|
307
|
+
`worker-src 'self' blob:`,
|
|
308
|
+
"upgrade-insecure-requests"
|
|
309
|
+
].join("; ");
|
|
310
|
+
}
|
|
311
|
+
async function buildScriptDirectory(sourceDirectory, outputDirectory, passes, root = sourceDirectory) {
|
|
312
|
+
for (const entry of await (0, node_fs_promises.readdir)(sourceDirectory, { withFileTypes: true })) {
|
|
313
|
+
const source = (0, node_path.join)(sourceDirectory, entry.name);
|
|
314
|
+
if (entry.isDirectory()) {
|
|
315
|
+
await buildScriptDirectory(source, outputDirectory, passes, root);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (!entry.isFile() || entry.name.endsWith(".d.ts")) continue;
|
|
319
|
+
const relativePath = (0, node_path.relative)(root, source);
|
|
320
|
+
const extension = (0, node_path.extname)(relativePath);
|
|
321
|
+
const output = (0, node_path.join)(outputDirectory, /\.[cm]?[jt]sx?$/.test(extension) ? `${relativePath.slice(0, -extension.length)}.js` : relativePath);
|
|
322
|
+
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(output), { recursive: true });
|
|
323
|
+
if (/\.[cm]?[jt]sx?$/.test(extension)) await (0, node_fs_promises.writeFile)(output, await minifyJs(source, { passes }));
|
|
324
|
+
else await (0, node_fs_promises.cp)(source, output);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
async function contentBuildId(outputDirectory, files, configuration) {
|
|
328
|
+
const hash = (0, node_crypto.createHash)("sha256");
|
|
329
|
+
hash.update(JSON.stringify(configuration));
|
|
330
|
+
for (const file of files) {
|
|
331
|
+
hash.update(file);
|
|
332
|
+
hash.update(await (0, node_fs_promises.readFile)((0, node_path.join)(outputDirectory, ...file.slice(1).split("/"))));
|
|
333
|
+
}
|
|
334
|
+
return hash.digest("hex");
|
|
335
|
+
}
|
|
223
336
|
async function publicFiles(directory, root = directory) {
|
|
224
337
|
const entries = await (0, node_fs_promises.readdir)(directory, { withFileTypes: true });
|
|
225
338
|
const files = [];
|
|
@@ -253,6 +366,118 @@ function globRule(pattern) {
|
|
|
253
366
|
source: `${source}$`
|
|
254
367
|
};
|
|
255
368
|
}
|
|
369
|
+
function functionExpression(callback) {
|
|
370
|
+
const source = callback.toString();
|
|
371
|
+
if (/^(?:async\s+)?function\b|^(?:async\s+)?\(/.test(source)) return `(${source})`;
|
|
372
|
+
if (source.startsWith("async ")) return `(async function ${source.slice(6)})`;
|
|
373
|
+
return `(function ${source})`;
|
|
374
|
+
}
|
|
375
|
+
function localizeConfig(config, language, languages) {
|
|
376
|
+
const get = (value, empty) => localizedValue(value, language, config.defaultLanguage, empty);
|
|
377
|
+
const applicationName = get(config.applicationName, "");
|
|
378
|
+
const description = get(config.description, "");
|
|
379
|
+
const icon192 = get(config.icons.icon192, "");
|
|
380
|
+
const icon512 = get(config.icons.icon512, "");
|
|
381
|
+
const origin = get(config.origin, "");
|
|
382
|
+
const pageUrl = origin === "" ? "" : new URL(`/${language}`, origin).href;
|
|
383
|
+
const organizationLogo = origin === "" || icon512 === "" ? "" : new URL(icon512, origin).href;
|
|
384
|
+
const themeColor = get(config.themeColor, "");
|
|
385
|
+
const title = get(config.title, "");
|
|
386
|
+
return {
|
|
387
|
+
document: {
|
|
388
|
+
applicationName,
|
|
389
|
+
appleStatusBarStyle: get(config.appleStatusBarStyle, "black-translucent"),
|
|
390
|
+
appleTouchIconUrl: get(config.icons.appleTouchIconUrl, icon192),
|
|
391
|
+
bodyMarkup: get(config.bodyMarkup, ""),
|
|
392
|
+
colorScheme: get(config.colorScheme, "light dark"),
|
|
393
|
+
headMarkup: get(config.headMarkup, ""),
|
|
394
|
+
iconUrl: get(config.icons.iconUrl, icon512),
|
|
395
|
+
maskIconColor: themeColor,
|
|
396
|
+
maskIconUrl: get(config.icons.maskIconUrl, ""),
|
|
397
|
+
seo: {
|
|
398
|
+
jsonLD: {
|
|
399
|
+
application: {
|
|
400
|
+
applicationCategory: get(config.application?.category, ""),
|
|
401
|
+
browserRequirements: get(config.application?.browserRequirements, ""),
|
|
402
|
+
featureList: get(config.application?.featureList, []),
|
|
403
|
+
inLanguage: languages,
|
|
404
|
+
name: applicationName,
|
|
405
|
+
operatingSystem: get(config.application?.operatingSystem, ""),
|
|
406
|
+
url: origin
|
|
407
|
+
},
|
|
408
|
+
organization: {
|
|
409
|
+
logo: get(config.organization?.logoUrl, organizationLogo),
|
|
410
|
+
name: get(config.organization?.name, applicationName),
|
|
411
|
+
url: get(config.organization?.url, origin)
|
|
412
|
+
},
|
|
413
|
+
page: {
|
|
414
|
+
description,
|
|
415
|
+
inLanguage: language,
|
|
416
|
+
name: title,
|
|
417
|
+
url: pageUrl
|
|
418
|
+
},
|
|
419
|
+
site: {
|
|
420
|
+
name: applicationName,
|
|
421
|
+
url: origin
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
languageLinks: {
|
|
425
|
+
alternateLanguages: languages,
|
|
426
|
+
canonicalLanguage: config.canonicalLanguage,
|
|
427
|
+
defaultLanguage: config.defaultLanguage,
|
|
428
|
+
host: origin === "" ? "" : new URL(origin).host
|
|
429
|
+
},
|
|
430
|
+
openGraph: {
|
|
431
|
+
description,
|
|
432
|
+
imageAlt: get(config.socialImage.alt, ""),
|
|
433
|
+
imageHeight: get(config.socialImage.height, 630),
|
|
434
|
+
imageUrl: get(config.socialImage.url, ""),
|
|
435
|
+
imageWidth: get(config.socialImage.width, 1200),
|
|
436
|
+
locale: get(config.openGraphLocale, ""),
|
|
437
|
+
siteName: applicationName,
|
|
438
|
+
title,
|
|
439
|
+
url: pageUrl
|
|
440
|
+
},
|
|
441
|
+
twitter: {
|
|
442
|
+
creator: get(config.twitter.creator, ""),
|
|
443
|
+
description,
|
|
444
|
+
imageAlt: get(config.socialImage.alt, ""),
|
|
445
|
+
imageUrl: get(config.socialImage.url, ""),
|
|
446
|
+
site: get(config.twitter.site, ""),
|
|
447
|
+
title,
|
|
448
|
+
url: pageUrl
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
themeColor,
|
|
452
|
+
title
|
|
453
|
+
},
|
|
454
|
+
manifest: {
|
|
455
|
+
backgroundColor: get(config.backgroundColor, themeColor),
|
|
456
|
+
categories: get(config.manifest?.categories, []),
|
|
457
|
+
description,
|
|
458
|
+
display: get(config.manifest?.display, "standalone"),
|
|
459
|
+
icon192,
|
|
460
|
+
icon512,
|
|
461
|
+
id: get(config.manifest?.id, "/"),
|
|
462
|
+
lang: language,
|
|
463
|
+
maskableIcon512: get(config.icons.maskableIcon512, icon512),
|
|
464
|
+
name: applicationName,
|
|
465
|
+
orientation: get(config.manifest?.orientation, "any"),
|
|
466
|
+
scope: get(config.manifest?.scope, "/"),
|
|
467
|
+
screenshots: get(config.manifest?.screenshots, []),
|
|
468
|
+
shortName: get(config.shortName, applicationName),
|
|
469
|
+
shortcuts: get(config.manifest?.shortcuts, []),
|
|
470
|
+
startUrl: `/${language}`,
|
|
471
|
+
themeColor
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function localizedValue(value, language, defaultLanguage, empty) {
|
|
476
|
+
if (value === void 0) return empty;
|
|
477
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
478
|
+
const values = value;
|
|
479
|
+
return values[language] ?? values[defaultLanguage] ?? empty;
|
|
480
|
+
}
|
|
256
481
|
//#endregion
|
|
257
482
|
exports.pwaize = pwaize;
|
|
258
483
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["build","transform","minify","build","fileURLToPath","minify","join","mkdir","cp","basename","writeFile","documentMarkup","existsSync","readdir","relative","sep"],"sources":["../src/minifyCss/index.ts","../src/minifyHtml/index.ts","../src/minifyJs/index.ts","../src/webManifest/index.ts","../src/index.ts"],"sourcesContent":["import type { PathLike } from 'node:fs'\nimport { build } from 'esbuild'\nimport { transform } from 'lightningcss'\n\n/** Bundles and minifies a CSS entrypoint into a dense string. */\nexport default async function minifyCss(entrypoint: PathLike): Promise<string> {\n const bundled = await build({\n entryPoints: [entrypoint.toString()],\n bundle: true,\n legalComments: 'none',\n minify: true,\n treeShaking: true,\n write: false,\n external: ['/assets/*'],\n })\n const { code } = transform({\n code: bundled.outputFiles[0].contents,\n filename: entrypoint.toString(),\n minify: true,\n })\n\n return new TextDecoder().decode(code).trim()\n}\n","import { minify } from 'html-minifier-terser'\n\n/** Minifies a complete HTML document, including inline CSS and JavaScript. */\nexport default async function minifyHtml(source: string): Promise<string> {\n return minify(source, {\n collapseBooleanAttributes: true,\n collapseInlineTagWhitespace: true,\n collapseWhitespace: true,\n decodeEntities: true,\n html5: true,\n minifyCSS: true,\n minifyJS: {\n compress: {\n dead_code: true,\n passes: 3,\n toplevel: true,\n unused: true,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n },\n removeAttributeQuotes: true,\n removeComments: true,\n removeEmptyAttributes: true,\n removeRedundantAttributes: true,\n sortAttributes: true,\n sortClassName: true,\n useShortDoctype: true,\n })\n}\n","import type { PathLike } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { build } from 'esbuild'\nimport { minify } from 'terser'\n\ntype JavaScriptInput = PathLike | { source: string }\n\ntype MinifyJsOptions = {\n define?: Record<string, string>\n passes?: number\n}\n\n/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */\nexport default async function minifyJs(\n input: JavaScriptInput,\n { define, passes = 3 }: MinifyJsOptions = {}\n): Promise<string> {\n const bundled = await build({\n ...(typeof input === 'object' && 'source' in input\n ? { stdin: { contents: input.source, resolveDir: process.cwd() } }\n : {\n entryPoints: [\n input instanceof URL ? fileURLToPath(input) : input.toString(),\n ],\n }),\n bundle: true,\n define,\n format: 'esm',\n legalComments: 'none',\n minify: true,\n platform: 'browser',\n treeShaking: true,\n write: false,\n })\n\n let output = bundled.outputFiles[0].text\n\n for (let round = 0; round < passes; round += 1) {\n const result = await minify(output, {\n compress: {\n dead_code: true,\n passes,\n toplevel: true,\n unused: true,\n },\n ecma: 2024,\n format: {\n beautify: false,\n comments: false,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n })\n\n if (result.code === undefined) {\n throw new Error('Terser did not produce JavaScript output')\n }\n\n output = result.code\n }\n\n return output\n}\n","import type { BCP47LanguageTag } from '@sovereignbase/utils'\n\ntype Path = `/${string}`\ntype ImageURL = Path | `https://${string}`\n\nexport interface WebManifestScreenshot {\n src: ImageURL\n sizes: `${number}x${number}`\n type?: `image/${string}`\n form_factor?: 'narrow' | 'wide'\n label?: string\n}\n\nexport interface WebManifestShortcut {\n name: string\n url: Path\n description?: string\n icons?: {\n src: ImageURL\n sizes: `${number}x${number}` | 'any'\n type?: `image/${string}`\n }[]\n}\n\nexport interface WebManifestOptions {\n name: string\n shortName: string\n description: string\n startUrl: Path\n themeColor: string\n icon192: ImageURL\n icon512: ImageURL\n maskableIcon512: ImageURL\n id?: Path\n scope?: Path\n backgroundColor?: string\n lang?: BCP47LanguageTag\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n orientation?:\n | 'any'\n | 'natural'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape'\n | 'landscape-primary'\n | 'landscape-secondary'\n categories?: string[]\n screenshots?: WebManifestScreenshot[]\n shortcuts?: WebManifestShortcut[]\n}\n\n/**\n * Generates a standards-based Web App Manifest JSON string.\n */\nexport const webManifest = ({\n name,\n shortName,\n description,\n startUrl,\n themeColor,\n icon192,\n icon512,\n maskableIcon512,\n id = '/',\n scope = '/',\n backgroundColor = themeColor,\n lang,\n display = 'standalone',\n orientation,\n categories,\n screenshots,\n shortcuts,\n}: WebManifestOptions): string =>\n JSON.stringify({\n id,\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope,\n display,\n theme_color: themeColor,\n background_color: backgroundColor,\n ...(lang ? { lang } : {}),\n ...(orientation ? { orientation } : {}),\n ...(categories?.length ? { categories } : {}),\n ...(screenshots?.length ? { screenshots } : {}),\n ...(shortcuts?.length ? { shortcuts } : {}),\n icons: [\n {\n src: icon192,\n sizes: '192x192',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: icon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: maskableIcon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ],\n })\n","import { existsSync, type PathLike } from 'node:fs'\nimport { cp, mkdir, readdir, writeFile } from 'node:fs/promises'\nimport { basename, join, relative, sep } from 'node:path'\nimport type { BCP47LanguageTag } from '@sovereignbase/utils'\nimport type { DocumentMarkupOptions } from './.types/index.js'\nimport { documentMarkup } from './htmlDocument/index.js'\nimport minifyCss from './minifyCss/index.js'\nimport minifyHtml from './minifyHtml/index.js'\nimport minifyJs from './minifyJs/index.js'\nimport { webManifest, type WebManifestOptions } from './webManifest/index.js'\n\nexport async function pwaize(config: PWAizeConfig): Promise<void> {\n const outputDirectory = join(config.outDir.toString(), 'web')\n const buildId = crypto.randomUUID()\n const minifyPasses = config.minifyPasses ?? 3\n const serviceWorkerPath = '/ServiceWorker'\n\n await mkdir(outputDirectory, { recursive: true })\n\n for (const directory of [config.assetsDir, config.i18nDir]) {\n if (directory === undefined) continue\n\n const sourceDirectory = directory.toString()\n await cp(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n {\n recursive: true,\n }\n )\n }\n\n const stylesheet = await minifyCss(config.stylesheet)\n const entrypoint = await minifyJs(config.entrypoint, {\n passes: minifyPasses,\n })\n const installer = await minifyJs(\n {\n source: `const registration=await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:\"/\",type:\"module\"});await navigator.serviceWorker.ready;if(!navigator.serviceWorker.controller)location.reload();`,\n },\n { passes: minifyPasses }\n )\n const languages = [config.defaultLanguage, ...config.alternateLanguages]\n\n for (const language of languages) {\n const localized = config.languages[language]\n if (localized === undefined) {\n throw new Error(`Missing PWA configuration for language \"${language}\"`)\n }\n\n const languageDirectory = join(outputDirectory, language)\n const manifestPath = `/${language}/manifest.webmanifest` as const\n const manifest = webManifest({\n ...localized.manifest,\n lang: language,\n })\n\n await mkdir(languageDirectory, { recursive: true })\n await writeFile(join(languageDirectory, 'manifest.webmanifest'), manifest)\n\n const installerDocument = await minifyHtml(\n await documentMarkup({\n ...localized.document,\n language,\n stylesheet: '',\n entrypoint: installer,\n manifestUrl: manifestPath,\n })\n )\n\n await writeFile(join(languageDirectory, 'index.html'), installerDocument)\n\n if (language === config.defaultLanguage) {\n await writeFile(join(outputDirectory, 'index.html'), installerDocument)\n await writeFile(join(outputDirectory, 'manifest.webmanifest'), manifest)\n }\n }\n\n const buildIdPath = join(\n outputDirectory,\n '@sovereignbase',\n 'pwa',\n 'pwaize-build-id.txt'\n )\n await mkdir(join(outputDirectory, '@sovereignbase', 'pwa'), {\n recursive: true,\n })\n await writeFile(buildIdPath, buildId)\n\n if (config._headersFile === true) {\n await writeFile(\n join(outputDirectory, '_headers'),\n `/${serviceWorkerPath.slice(1)}\\n Cache-Control: no-cache\\n Content-Type: text/javascript;charset=UTF-8\\n\\n/*\\n X-Content-Type-Options: nosniff\\n`\n )\n }\n\n const precache = [\n ...(await publicFiles(outputDirectory)),\n ...(config.serviceWorker?.precache ?? []),\n ]\n const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule)\n const compiledServiceWorker = new URL(\n './serviceWorker/entrypoint.js',\n import.meta.url\n )\n const serviceWorker = await minifyJs(\n existsSync(compiledServiceWorker)\n ? compiledServiceWorker\n : new URL('./serviceWorker/entrypoint.ts', import.meta.url),\n {\n define: {\n buildId: JSON.stringify(buildId),\n buildIdUrl: JSON.stringify('/@sovereignbase/pwa/pwaize-build-id.txt'),\n bypassRules: JSON.stringify(bypassRules),\n customInitialize:\n config.serviceWorker?.initialize === undefined\n ? 'undefined'\n : `(${config.serviceWorker.initialize.toString()})`,\n customWaitUntil:\n config.serviceWorker?.waitUntil === undefined\n ? 'undefined'\n : `(${config.serviceWorker.waitUntil.toString()})`,\n defaultLanguage: JSON.stringify(config.defaultLanguage),\n documentOptions: JSON.stringify(\n Object.fromEntries(\n languages.map((language) => [\n language,\n config.languages[language].document,\n ])\n )\n ),\n entrypoint: JSON.stringify(entrypoint),\n precache: JSON.stringify(precache),\n stylesheet: JSON.stringify(stylesheet),\n },\n passes: minifyPasses,\n }\n )\n\n await writeFile(\n join(outputDirectory, serviceWorkerPath.slice(1)),\n serviceWorker\n )\n}\n\nasync function publicFiles(\n directory: string,\n root = directory\n): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true })\n const files: string[] = []\n\n for (const entry of entries) {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) {\n files.push(...(await publicFiles(path, root)))\n } else if (entry.isFile() && entry.name !== '_headers') {\n files.push(`/${relative(root, path).split(sep).join('/')}`)\n }\n }\n\n return files.sort()\n}\n\nfunction globRule(pattern: string | RegExp): {\n absolute: boolean\n flags: string\n source: string\n} {\n if (pattern instanceof RegExp) {\n return {\n absolute: true,\n flags: pattern.flags,\n source: pattern.source,\n }\n }\n\n let source = '^'\n for (let index = 0; index < pattern.length; index += 1) {\n const character = pattern[index]\n\n if (character === '*') {\n if (pattern[index + 1] === '*') {\n source += '.*'\n index += 1\n } else {\n source += '[^/]*'\n }\n } else if (character === '?') {\n source += '.'\n } else {\n source += character.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n }\n }\n\n return {\n absolute: pattern.includes('://'),\n flags: '',\n source: `${source}$`,\n }\n}\n\nexport type PWAizeConfig = {\n defaultLanguage: BCP47LanguageTag\n canonicalLanguage: BCP47LanguageTag\n alternateLanguages: BCP47LanguageTag[]\n\n languages: Record<\n string,\n {\n document: Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n manifest: Omit<WebManifestOptions, 'lang'>\n }\n >\n\n stylesheet: PathLike\n entrypoint: PathLike\n outDir: PathLike\n\n assetsDir?: PathLike\n i18nDir?: PathLike\n minifyPasses?: number\n\n serviceWorker?: {\n bypass?: Array<string | RegExp>\n precache?: `/${string}`[]\n initialize?: () => void\n waitUntil?: () => Promise<void>\n }\n\n _headersFile?: boolean\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Bytes","minifiedOutputs","build","transform","minifiedOutputs","minify","build","fileURLToPath","minify","join","mkdir","cp","basename","writeFile","documentMarkup","existsSync","readdir","relative","extname","dirname","createHash","readFile","sep"],"sources":["../src/cspHash/index.ts","../src/minifyCss/index.ts","../src/minifyHtml/index.ts","../src/minifyJs/index.ts","../src/webManifest/index.ts","../src/index.ts"],"sourcesContent":["import { Bytes } from '@sovereignbase/bytecodec'\n\nexport const cspHash = async (source: string): Promise<`sha256-${string}`> => {\n const digest = await crypto.subtle.digest(\n 'SHA-256',\n Bytes.fromString(source) as BufferSource\n )\n\n return `sha256-${Bytes.toBase64String(digest)}`\n}\n","import type { PathLike } from 'node:fs'\nimport { build } from 'esbuild'\nimport { transform } from 'lightningcss'\n\nconst minifiedOutputs = new Map<string, string>()\n\n/** Bundles and minifies a CSS entrypoint into a dense string. */\nexport default async function minifyCss(entrypoint: PathLike): Promise<string> {\n const bundled = await build({\n entryPoints: [entrypoint.toString()],\n bundle: true,\n legalComments: 'none',\n minify: true,\n treeShaking: true,\n write: false,\n external: ['/assets/*'],\n })\n const source = bundled.outputFiles[0].text\n const cached = minifiedOutputs.get(source)\n if (cached !== undefined) return cached\n\n const { code } = transform({\n code: bundled.outputFiles[0].contents,\n filename: entrypoint.toString(),\n minify: true,\n })\n\n const output = new TextDecoder().decode(code).trim()\n minifiedOutputs.set(source, output)\n return output\n}\n","import { minify } from 'html-minifier-terser'\n\nconst minifiedOutputs = new Map<string, string>()\n\n/** Minifies a complete HTML document, including inline CSS and JavaScript. */\nexport default async function minifyHtml(source: string): Promise<string> {\n const cached = minifiedOutputs.get(source)\n if (cached !== undefined) return cached\n\n const output = await minify(source, {\n collapseBooleanAttributes: true,\n collapseInlineTagWhitespace: true,\n collapseWhitespace: true,\n decodeEntities: true,\n html5: true,\n minifyCSS: true,\n minifyJS: {\n compress: {\n dead_code: true,\n passes: 3,\n toplevel: true,\n unused: true,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n },\n removeAttributeQuotes: true,\n removeComments: true,\n removeEmptyAttributes: true,\n removeRedundantAttributes: true,\n sortAttributes: true,\n sortClassName: true,\n useShortDoctype: true,\n })\n minifiedOutputs.set(source, output)\n return output\n}\n","import type { PathLike } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { build } from 'esbuild'\nimport { minify } from 'terser'\n\nconst minifiedOutputs = new Map<string, string>()\n\ntype JavaScriptInput = PathLike | { source: string }\n\ntype MinifyJsOptions = {\n banner?: string\n define?: Record<string, string>\n passes?: number\n}\n\n/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */\nexport default async function minifyJs(\n input: JavaScriptInput,\n { banner, define, passes = 3 }: MinifyJsOptions = {}\n): Promise<string> {\n const bundled = await build({\n ...(typeof input === 'object' && 'source' in input\n ? { stdin: { contents: input.source, resolveDir: process.cwd() } }\n : {\n entryPoints: [\n input instanceof URL ? fileURLToPath(input) : input.toString(),\n ],\n }),\n bundle: true,\n banner: banner === undefined ? undefined : { js: banner },\n define,\n format: 'esm',\n legalComments: 'none',\n minify: true,\n platform: 'browser',\n treeShaking: true,\n write: false,\n })\n\n const output = bundled.outputFiles[0].text\n const cacheKey = `${passes}\\0${output}`\n const cached = minifiedOutputs.get(cacheKey)\n if (cached !== undefined) return cached\n\n const result = await repeatedlyMinify(output, passes)\n minifiedOutputs.set(cacheKey, result)\n return result\n}\n\nasync function repeatedlyMinify(\n source: string,\n passes: number\n): Promise<string> {\n let output = source\n\n for (let round = 0; round < passes; round += 1) {\n const result = await minify(output, {\n compress: {\n dead_code: true,\n passes,\n toplevel: true,\n unused: true,\n },\n ecma: 2024,\n format: {\n beautify: false,\n comments: false,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n })\n\n /* v8 ignore next 3 -- Terser returns code or rejects for this input form. */\n if (result.code === undefined) {\n throw new Error('Terser did not produce JavaScript output')\n }\n\n output = result.code\n }\n\n return output\n}\n","import type { BCP47LanguageTag } from '@sovereignbase/utils'\n\ntype Path = `/${string}`\ntype ImageURL = Path | `https://${string}`\n\nexport interface WebManifestScreenshot {\n src: ImageURL\n sizes: `${number}x${number}`\n type?: `image/${string}`\n form_factor?: 'narrow' | 'wide'\n label?: string\n}\n\nexport interface WebManifestShortcut {\n name: string\n url: Path\n description?: string\n icons?: {\n src: ImageURL\n sizes: `${number}x${number}` | 'any'\n type?: `image/${string}`\n }[]\n}\n\nexport interface WebManifestOptions {\n name: string\n shortName: string\n description: string\n startUrl: Path\n themeColor: string\n icon192: ImageURL\n icon512: ImageURL\n maskableIcon512: ImageURL\n id?: Path\n scope?: Path\n backgroundColor?: string\n lang?: BCP47LanguageTag\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n orientation?:\n | 'any'\n | 'natural'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape'\n | 'landscape-primary'\n | 'landscape-secondary'\n categories?: string[]\n screenshots?: WebManifestScreenshot[]\n shortcuts?: WebManifestShortcut[]\n}\n\n/**\n * Generates a standards-based Web App Manifest JSON string.\n */\nexport const webManifest = ({\n name,\n shortName,\n description,\n startUrl,\n themeColor,\n icon192,\n icon512,\n maskableIcon512,\n id = '/',\n scope = '/',\n backgroundColor = themeColor,\n lang,\n display = 'standalone',\n orientation,\n categories,\n screenshots,\n shortcuts,\n}: WebManifestOptions): string =>\n JSON.stringify({\n id,\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope,\n display,\n theme_color: themeColor,\n background_color: backgroundColor,\n ...(lang ? { lang } : {}),\n ...(orientation ? { orientation } : {}),\n ...(categories?.length ? { categories } : {}),\n ...(screenshots?.length ? { screenshots } : {}),\n ...(shortcuts?.length ? { shortcuts } : {}),\n icons: [\n {\n src: icon192,\n sizes: '192x192',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: icon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: maskableIcon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ],\n })\n","import { createHash } from 'node:crypto'\nimport { existsSync, type PathLike } from 'node:fs'\nimport { cp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises'\nimport { basename, dirname, extname, join, relative, sep } from 'node:path'\nimport type { BCP47LanguageTag, OpenGraphLocale } from '@sovereignbase/utils'\nimport type {\n DocumentMarkupOptions,\n HTTPSUrl,\n URLPath,\n} from './.types/index.js'\nimport { cspHash } from './cspHash/index.js'\nimport { documentMarkup } from './htmlDocument/index.js'\nimport minifyCss from './minifyCss/index.js'\nimport minifyHtml from './minifyHtml/index.js'\nimport minifyJs from './minifyJs/index.js'\nimport {\n webManifest,\n type WebManifestOptions,\n type WebManifestScreenshot,\n type WebManifestShortcut,\n} from './webManifest/index.js'\n\nexport async function pwaize(config: PWAizeConfig): Promise<void> {\n const outputDirectory = join(config.outDir.toString(), 'web')\n const languages = [\n ...new Set([config.defaultLanguage, ...config.alternateLanguages]),\n ]\n const minifyPasses = config.minifyPasses ?? 3\n const buildIdUrl = '/@sovereignbase/pwa/pwaize-build-id.txt'\n const serviceWorkerPath = '/ServiceWorker'\n\n await mkdir(outputDirectory, { recursive: true })\n\n if (config.assetsDir !== undefined) {\n const sourceDirectory = config.assetsDir.toString()\n await cp(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n { recursive: true }\n )\n }\n\n if (config.i18nDir !== undefined) {\n const sourceDirectory = config.i18nDir.toString()\n await buildScriptDirectory(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n minifyPasses\n )\n }\n\n const stylesheet = await minifyCss(config.stylesheet)\n const entrypoint = await minifyJs(config.entrypoint, {\n passes: minifyPasses,\n })\n const installer = await minifyJs(\n {\n source: `await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:\"/\",type:\"module\"});await navigator.serviceWorker.ready;location.reload();`,\n },\n { passes: minifyPasses }\n )\n const documentOptions: Record<\n string,\n Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n > = {}\n const contentSecurityPolicies: Record<string, string> = {}\n const installerDocuments: string[] = []\n\n for (const language of languages) {\n const localized = localizeConfig(config, language, languages)\n const languageDirectory = join(outputDirectory, language)\n const manifestPath = `/${language}/manifest.webmanifest` as const\n const manifest = webManifest(localized.manifest)\n documentOptions[language] = localized.document\n\n await mkdir(languageDirectory, { recursive: true })\n await writeFile(join(languageDirectory, 'manifest.webmanifest'), manifest)\n\n const installerDocument = await minifyHtml(\n await documentMarkup({\n ...localized.document,\n entrypoint: installer,\n language,\n manifestUrl: manifestPath,\n })\n )\n const applicationDocument = await documentMarkup({\n ...localized.document,\n entrypoint,\n language,\n manifestUrl: manifestPath,\n stylesheet,\n })\n contentSecurityPolicies[language] = await contentSecurityPolicy([\n applicationDocument,\n ])\n installerDocuments.push(installerDocument)\n await writeFile(join(languageDirectory, 'index.html'), installerDocument)\n\n if (language === config.defaultLanguage) {\n await writeFile(join(outputDirectory, 'index.html'), installerDocument)\n await writeFile(join(outputDirectory, 'manifest.webmanifest'), manifest)\n }\n }\n\n if (config._headersFile === true) {\n const installerContentSecurityPolicy =\n await contentSecurityPolicy(installerDocuments)\n const assetsHeaders =\n config.assetsDir === undefined\n ? ''\n : `/${basename(config.assetsDir.toString())}/*\\n Cache-Control: public, max-age=31536000, immutable\\n\\n`\n await writeFile(\n join(outputDirectory, '_headers'),\n `/${serviceWorkerPath.slice(1)}\\n Cache-Control: no-cache\\n Content-Type: text/javascript;charset=UTF-8\\n\\n${buildIdUrl}\\n Cache-Control: no-cache, no-store, must-revalidate\\n Content-Type: text/plain;charset=UTF-8\\n\\n${assetsHeaders}/*\\n Content-Security-Policy: ${installerContentSecurityPolicy}\\n X-Content-Type-Options: nosniff\\n`\n )\n }\n\n const generatedFiles = (await publicFiles(outputDirectory)).filter(\n (url) => url !== serviceWorkerPath && url !== buildIdUrl\n )\n const precache = [\n ...new Set([...generatedFiles, ...(config.serviceWorker?.precache ?? [])]),\n ].sort()\n const staticRoutes = [\n ...new Set(\n precache\n .map((url) => new URL(url, 'https://pwaize.invalid').pathname)\n .filter((url) => !url.endsWith('/index.html') && url !== '/index.html')\n ),\n ].sort()\n const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule)\n const initialize =\n config.serviceWorker?.initialize === undefined\n ? 'undefined'\n : functionExpression(config.serviceWorker.initialize)\n const waitUntil =\n config.serviceWorker?.waitUntil === undefined\n ? 'undefined'\n : functionExpression(config.serviceWorker.waitUntil)\n const buildId = await contentBuildId(outputDirectory, generatedFiles, {\n bypassRules,\n contentSecurityPolicies,\n documentOptions,\n entrypoint,\n initialize,\n precache,\n staticRoutes,\n stylesheet,\n waitUntil,\n })\n const buildIdDirectory = join(outputDirectory, '@sovereignbase', 'pwa')\n await mkdir(buildIdDirectory, { recursive: true })\n await writeFile(join(buildIdDirectory, 'pwaize-build-id.txt'), buildId)\n const compiledServiceWorker = new URL(\n './serviceWorker/entrypoint.js',\n import.meta.url\n )\n const serviceWorker = await minifyJs(\n /* v8 ignore next -- the packaged .js path is exercised by runtime tests */\n existsSync(compiledServiceWorker)\n ? compiledServiceWorker\n : new URL('./serviceWorker/entrypoint.ts', import.meta.url),\n {\n banner: `const __pwaInitialize=${initialize},__pwaWaitUntil=${waitUntil};`,\n define: {\n buildId: JSON.stringify(buildId),\n buildIdUrl: JSON.stringify(buildIdUrl),\n bypassRules: JSON.stringify(bypassRules),\n customInitialize: '__pwaInitialize',\n customWaitUntil: '__pwaWaitUntil',\n defaultLanguage: JSON.stringify(config.defaultLanguage),\n contentSecurityPolicies: JSON.stringify(contentSecurityPolicies),\n documentOptions: JSON.stringify(documentOptions),\n entrypoint: JSON.stringify(entrypoint),\n precache: JSON.stringify(precache),\n staticRoutes: JSON.stringify(staticRoutes),\n stylesheet: JSON.stringify(stylesheet),\n },\n passes: minifyPasses,\n }\n )\n\n await writeFile(\n join(outputDirectory, serviceWorkerPath.slice(1)),\n serviceWorker\n )\n}\n\nasync function contentSecurityPolicy(documents: string[]): Promise<string> {\n const inlineScripts = documents.flatMap((document) =>\n [...document.matchAll(/<script\\b[^>]*>([\\s\\S]*?)<\\/script>/gi)].map(\n (match) => match[1]\n )\n )\n const inlineStyles = documents.flatMap((document) =>\n [...document.matchAll(/<style\\b[^>]*>([\\s\\S]*?)<\\/style>/gi)].map(\n (match) => match[1]\n )\n )\n const hashes = async (sources: string[]): Promise<string> =>\n (\n await Promise.all(\n [...new Set(sources.length === 0 ? [''] : sources)].map(cspHash)\n )\n )\n .map((hash) => `'${hash}'`)\n .join(' ')\n\n return [\n `default-src 'self'`,\n `base-uri 'self'`,\n `connect-src 'self' https: wss:`,\n `font-src 'self' data:`,\n `form-action 'self'`,\n `frame-ancestors 'none'`,\n `img-src 'self' data: https:`,\n `manifest-src 'self'`,\n `media-src 'self' data: blob: https:`,\n `object-src 'none'`,\n `script-src 'self' 'unsafe-inline' ${await hashes(inlineScripts)}`,\n `style-src 'self' 'unsafe-inline' ${await hashes(inlineStyles)}`,\n `worker-src 'self' blob:`,\n 'upgrade-insecure-requests',\n ].join('; ')\n}\n\nasync function buildScriptDirectory(\n sourceDirectory: string,\n outputDirectory: string,\n passes: number,\n root = sourceDirectory\n): Promise<void> {\n for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {\n const source = join(sourceDirectory, entry.name)\n if (entry.isDirectory()) {\n await buildScriptDirectory(source, outputDirectory, passes, root)\n continue\n }\n if (!entry.isFile() || entry.name.endsWith('.d.ts')) continue\n\n const relativePath = relative(root, source)\n const extension = extname(relativePath)\n const output = join(\n outputDirectory,\n /\\.[cm]?[jt]sx?$/.test(extension)\n ? `${relativePath.slice(0, -extension.length)}.js`\n : relativePath\n )\n await mkdir(dirname(output), { recursive: true })\n if (/\\.[cm]?[jt]sx?$/.test(extension)) {\n await writeFile(output, await minifyJs(source, { passes }))\n } else {\n await cp(source, output)\n }\n }\n}\n\nasync function contentBuildId(\n outputDirectory: string,\n files: string[],\n configuration: unknown\n): Promise<string> {\n const hash = createHash('sha256')\n hash.update(JSON.stringify(configuration))\n for (const file of files) {\n hash.update(file)\n hash.update(\n await readFile(join(outputDirectory, ...file.slice(1).split('/')))\n )\n }\n return hash.digest('hex')\n}\n\nasync function publicFiles(\n directory: string,\n root = directory\n): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true })\n const files: string[] = []\n\n for (const entry of entries) {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) {\n files.push(...(await publicFiles(path, root)))\n } else if (entry.isFile() && entry.name !== '_headers') {\n files.push(`/${relative(root, path).split(sep).join('/')}`)\n }\n }\n\n return files.sort()\n}\n\nfunction globRule(pattern: string | RegExp): {\n absolute: boolean\n flags: string\n source: string\n} {\n if (pattern instanceof RegExp) {\n return { absolute: true, flags: pattern.flags, source: pattern.source }\n }\n\n let source = '^'\n for (let index = 0; index < pattern.length; index += 1) {\n const character = pattern[index]\n if (character === '*') {\n if (pattern[index + 1] === '*') {\n source += '.*'\n index += 1\n } else {\n source += '[^/]*'\n }\n } else if (character === '?') {\n source += '.'\n } else {\n source += character.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n }\n }\n\n return {\n absolute: pattern.includes('://'),\n flags: '',\n source: `${source}$`,\n }\n}\n\nfunction functionExpression(\n callback: (...arguments_: never[]) => unknown\n): string {\n const source = callback.toString()\n if (/^(?:async\\s+)?function\\b|^(?:async\\s+)?\\(/.test(source)) {\n return `(${source})`\n }\n if (source.startsWith('async ')) {\n return `(async function ${source.slice('async '.length)})`\n }\n return `(function ${source})`\n}\n\nfunction localizeConfig(\n config: PWAizeConfig,\n language: BCP47LanguageTag,\n languages: BCP47LanguageTag[]\n): {\n document: Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n manifest: WebManifestOptions\n} {\n const get = <T>(value: Localized<T> | undefined, empty: T): T =>\n localizedValue(value, language, config.defaultLanguage, empty)\n const applicationName = get(config.applicationName, '')\n const description = get(config.description, '')\n const icon192 = get<string>(config.icons.icon192, '')\n const icon512 = get<string>(config.icons.icon512, '')\n const origin = get<string>(config.origin, '')\n const pageUrl = (\n origin === '' ? '' : new URL(`/${language}`, origin).href\n ) as HTTPSUrl\n const organizationLogo = (\n origin === '' || icon512 === '' ? '' : new URL(icon512, origin).href\n ) as HTTPSUrl\n const themeColor = get(config.themeColor, '')\n const title = get(config.title, '')\n\n return {\n document: {\n applicationName,\n appleStatusBarStyle: get(config.appleStatusBarStyle, 'black-translucent'),\n appleTouchIconUrl: get(\n config.icons.appleTouchIconUrl,\n icon192 as URLPath\n ),\n bodyMarkup: get(config.bodyMarkup, ''),\n colorScheme: get(config.colorScheme, 'light dark'),\n headMarkup: get(config.headMarkup, ''),\n iconUrl: get(config.icons.iconUrl, icon512 as URLPath),\n maskIconColor: themeColor,\n maskIconUrl: get(config.icons.maskIconUrl, '' as URLPath),\n seo: {\n jsonLD: {\n application: {\n applicationCategory: get(config.application?.category, ''),\n browserRequirements: get(\n config.application?.browserRequirements,\n ''\n ),\n featureList: get(config.application?.featureList, []),\n inLanguage: languages,\n name: applicationName,\n operatingSystem: get(config.application?.operatingSystem, ''),\n url: origin as HTTPSUrl,\n },\n organization: {\n logo: get(config.organization?.logoUrl, organizationLogo),\n name: get(config.organization?.name, applicationName),\n url: get<string>(config.organization?.url, origin) as HTTPSUrl,\n },\n page: {\n description,\n inLanguage: language,\n name: title,\n url: pageUrl,\n },\n site: { name: applicationName, url: origin as HTTPSUrl },\n },\n languageLinks: {\n alternateLanguages: languages,\n canonicalLanguage: config.canonicalLanguage,\n defaultLanguage: config.defaultLanguage,\n host: (origin === ''\n ? ''\n : new URL(origin).host) as `${string}.${string}`,\n },\n openGraph: {\n description,\n imageAlt: get(config.socialImage.alt, ''),\n imageHeight: get(config.socialImage.height, 630),\n imageUrl: get(config.socialImage.url, '' as HTTPSUrl),\n imageWidth: get(config.socialImage.width, 1200),\n locale: get(config.openGraphLocale, '' as OpenGraphLocale),\n siteName: applicationName,\n title,\n url: pageUrl,\n },\n twitter: {\n creator: get(config.twitter.creator, '' as `@${string}`),\n description,\n imageAlt: get(config.socialImage.alt, ''),\n imageUrl: get(config.socialImage.url, '' as HTTPSUrl),\n site: get(config.twitter.site, '' as `@${string}`),\n title,\n url: pageUrl,\n },\n },\n themeColor,\n title,\n },\n manifest: {\n backgroundColor: get(config.backgroundColor, themeColor),\n categories: get(config.manifest?.categories, []),\n description,\n display: get(config.manifest?.display, 'standalone'),\n icon192: icon192 as URLPath,\n icon512: icon512 as URLPath,\n id: get(config.manifest?.id, '/' as URLPath),\n lang: language,\n maskableIcon512: get(config.icons.maskableIcon512, icon512 as URLPath),\n name: applicationName,\n orientation: get(config.manifest?.orientation, 'any'),\n scope: get(config.manifest?.scope, '/' as URLPath),\n screenshots: get(config.manifest?.screenshots, []),\n shortName: get(config.shortName, applicationName),\n shortcuts: get(config.manifest?.shortcuts, []),\n startUrl: `/${language}`,\n themeColor,\n },\n }\n}\n\nfunction localizedValue<T>(\n value: Localized<T> | undefined,\n language: BCP47LanguageTag,\n defaultLanguage: BCP47LanguageTag,\n empty: T\n): T {\n if (value === undefined) return empty\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return value as T\n }\n\n const values = value as Partial<Record<BCP47LanguageTag, T>>\n return values[language] ?? values[defaultLanguage] ?? empty\n}\n\nexport type Localized<T> = T | Partial<Record<BCP47LanguageTag, T>>\n\nexport type PWAizeConfig = {\n _headersFile?: boolean\n alternateLanguages: BCP47LanguageTag[]\n application?: {\n browserRequirements?: Localized<string>\n category?: Localized<string>\n featureList?: Localized<string[]>\n operatingSystem?: Localized<string>\n }\n applicationName: Localized<string>\n appleStatusBarStyle?: Localized<'black' | 'black-translucent' | 'default'>\n assetsDir?: PathLike\n backgroundColor?: Localized<string>\n bodyMarkup?: Localized<string>\n canonicalLanguage: BCP47LanguageTag\n colorScheme?: Localized<'dark' | 'dark light' | 'light' | 'light dark'>\n defaultLanguage: BCP47LanguageTag\n description: Localized<string>\n entrypoint: PathLike\n headMarkup?: Localized<string>\n i18nDir?: PathLike\n icons: {\n appleTouchIconUrl?: Localized<URLPath>\n icon192: Localized<URLPath>\n icon512: Localized<URLPath>\n iconUrl?: Localized<URLPath>\n maskableIcon512: Localized<URLPath>\n maskIconUrl?: Localized<URLPath>\n }\n manifest?: {\n categories?: Localized<string[]>\n display?: Localized<'browser' | 'fullscreen' | 'minimal-ui' | 'standalone'>\n id?: Localized<URLPath>\n orientation?: Localized<WebManifestOptions['orientation']>\n scope?: Localized<URLPath>\n screenshots?: Localized<WebManifestScreenshot[]>\n shortcuts?: Localized<WebManifestShortcut[]>\n }\n minifyPasses?: number\n openGraphLocale: Localized<OpenGraphLocale>\n organization?: {\n logoUrl?: Localized<HTTPSUrl>\n name?: Localized<string>\n url?: Localized<HTTPSUrl>\n }\n origin: Localized<HTTPSUrl>\n outDir: PathLike\n serviceWorker?: {\n bypass?: Array<string | RegExp>\n initialize?: () => void\n precache?: URLPath[]\n waitUntil?: () => Promise<void>\n }\n shortName?: Localized<string>\n socialImage: {\n alt: Localized<string>\n height?: Localized<number>\n url: Localized<HTTPSUrl>\n width?: Localized<number>\n }\n stylesheet: PathLike\n themeColor: Localized<string>\n title: Localized<string>\n twitter: {\n creator: Localized<`@${string}`>\n site: Localized<`@${string}`>\n }\n}\n"],"mappings":"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"}
|