pressy 0.1.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/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +835 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config-DlVehy4M.d.ts +41 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +757 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/client.d.ts +25 -0
- package/dist/runtime/client.js +660 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/offline.d.ts +17 -0
- package/dist/runtime/offline.js +171 -0
- package/dist/runtime/offline.js.map +1 -0
- package/dist/runtime/sw.d.ts +2 -0
- package/dist/runtime/sw.js +136 -0
- package/dist/runtime/sw.js.map +1 -0
- package/dist/types-CQs_xIit.d.ts +72 -0
- package/dist/vite/plugin.d.ts +6 -0
- package/dist/vite/plugin.js +738 -0
- package/dist/vite/plugin.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js","../src/config.ts","../src/vite/plugin.ts","../src/mdx/processor.ts","../src/runtime/offline-page.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","export interface SiteConfig {\n title: string\n url: string\n description?: string\n author?: string\n language?: string\n}\n\nexport interface PaginationConfig {\n defaultMode: 'scroll' | 'paginated'\n}\n\nexport interface ShopifyConfig {\n shopDomain: string\n storefrontAccessToken: string\n}\n\nexport interface PWAConfig {\n /** Enable PWA support (service worker, manifest, offline). Defaults to true. */\n enabled?: boolean\n /** Short name for the app (used on home screen). Defaults to site.title. */\n shortName?: string\n /** Theme color for the browser chrome. Defaults to '#ffffff'. */\n themeColor?: string\n /** Background color for splash screen. Defaults to '#ffffff'. */\n backgroundColor?: string\n /** Display mode. Defaults to 'standalone'. */\n display?: 'standalone' | 'minimal-ui' | 'fullscreen' | 'browser'\n /** Path to a custom 192x192 icon. */\n icon192?: string\n /** Path to a custom 512x512 icon. */\n icon512?: string\n}\n\nexport interface PressyConfig {\n site: SiteConfig\n pagination?: PaginationConfig\n shopify?: ShopifyConfig\n pwa?: PWAConfig\n outDir?: string\n contentDir?: string\n}\n\nexport function defineConfig(config: PressyConfig): PressyConfig {\n return {\n pagination: {\n defaultMode: 'scroll',\n },\n pwa: {\n enabled: true,\n themeColor: '#ffffff',\n backgroundColor: '#ffffff',\n display: 'standalone',\n },\n outDir: 'dist',\n contentDir: 'content',\n ...config,\n }\n}\n","import { Plugin, ViteDevServer } from 'vite'\nimport { resolve, join, relative, dirname } from 'path'\nimport { existsSync, readFileSync } from 'fs'\nimport { createHash } from 'crypto'\nimport { createRequire } from 'module'\n\nconst _require = createRequire(import.meta.url)\nimport fastGlob from 'fast-glob'\nimport yaml from 'yaml'\nimport matter from 'gray-matter'\nimport type { PressyConfig } from '../config.js'\nimport type { Book, Article, Chapter, ContentManifest, Route } from '../types.js'\nimport { compileMDX } from '../mdx/processor.js'\nimport { generateOfflinePage } from '../runtime/offline-page.js'\n\nconst VIRTUAL_MODULE_ID = 'virtual:pressy'\nconst RESOLVED_VIRTUAL_MODULE_ID = '\\0' + VIRTUAL_MODULE_ID\nconst VIRTUAL_ENTRY_ID = 'virtual:pressy-entry'\nconst RESOLVED_VIRTUAL_ENTRY_ID = '\\0' + VIRTUAL_ENTRY_ID\nconst VIRTUAL_ROUTE_PREFIX = 'virtual:pressy-route:'\nconst RESOLVED_ROUTE_PREFIX = '\\0' + VIRTUAL_ROUTE_PREFIX\nconst VIRTUAL_CHAPTER_MAP_PREFIX = 'virtual:pressy-chapter-map:'\nconst RESOLVED_CHAPTER_MAP_PREFIX = '\\0' + VIRTUAL_CHAPTER_MAP_PREFIX\n\nexport function pressyPlugin(config: PressyConfig): Plugin[] {\n let root: string\n let contentDir: string\n let manifest: ContentManifest = { books: [], articles: [] }\n let routes: Route[] = []\n\n const pwaEnabled = config.pwa?.enabled !== false\n const pwaConfig = {\n themeColor: config.pwa?.themeColor || '#ffffff',\n backgroundColor: config.pwa?.backgroundColor || '#ffffff',\n display: config.pwa?.display || 'standalone',\n shortName: config.pwa?.shortName || config.site.title,\n }\n\n const contentDiscovery = {\n async discoverContent(): Promise<ContentManifest> {\n const books = await this.discoverBooks()\n const articles = await this.discoverArticles()\n return { books, articles }\n },\n\n async discoverBooks(): Promise<Book[]> {\n const booksDir = join(contentDir, 'books')\n if (!existsSync(booksDir)) return []\n\n const bookDirs = await fastGlob('*', {\n cwd: booksDir,\n onlyDirectories: true,\n })\n\n const books: Book[] = []\n\n for (const bookSlug of bookDirs) {\n const bookPath = join(booksDir, bookSlug)\n const metadataPath = join(bookPath, '_book.yaml')\n\n if (!existsSync(metadataPath)) continue\n\n const metadataContent = readFileSync(metadataPath, 'utf-8')\n const metadata = yaml.parse(metadataContent)\n\n // Find chapters\n const chapterFiles = await fastGlob('*.mdx', {\n cwd: bookPath,\n ignore: ['_*.mdx'],\n })\n\n const chapters: Chapter[] = chapterFiles\n .map((file): Chapter | null => {\n const match = file.match(/^(\\d+)-(.+)\\.mdx$/)\n if (!match) return null\n\n const order = parseInt(match[1], 10)\n const slug = match[2]\n const filePath = join(bookPath, file)\n const content = readFileSync(filePath, 'utf-8')\n const { data } = matter(content)\n\n return {\n slug,\n title: data.title || slug.replace(/-/g, ' '),\n order,\n filePath,\n wordCount: content.split(/\\s+/).length,\n readingTime: Math.ceil(content.split(/\\s+/).length / 200),\n }\n })\n .filter((c): c is Chapter => c !== null)\n .sort((a, b) => a.order - b.order)\n\n const coverPath = existsSync(join(bookPath, 'cover.jpg'))\n ? join(bookPath, 'cover.jpg')\n : existsSync(join(bookPath, 'cover.png'))\n ? join(bookPath, 'cover.png')\n : undefined\n\n books.push({\n slug: bookSlug,\n metadata,\n chapters,\n basePath: bookPath,\n coverPath,\n })\n }\n\n return books\n },\n\n async discoverArticles(): Promise<Article[]> {\n const articlesDir = join(contentDir, 'articles')\n if (!existsSync(articlesDir)) return []\n\n const articleDirs = await fastGlob('*', {\n cwd: articlesDir,\n onlyDirectories: true,\n })\n\n const articles: Article[] = []\n\n for (const articleSlug of articleDirs) {\n const articlePath = join(articlesDir, articleSlug)\n const metadataPath = join(articlePath, '_article.yaml')\n const indexPath = join(articlePath, 'index.mdx')\n\n if (!existsSync(indexPath)) continue\n\n let metadata: Article['metadata']\n if (existsSync(metadataPath)) {\n metadata = yaml.parse(readFileSync(metadataPath, 'utf-8'))\n } else {\n const content = readFileSync(indexPath, 'utf-8')\n const { data } = matter(content)\n metadata = data as Article['metadata']\n }\n\n const content = readFileSync(indexPath, 'utf-8')\n\n articles.push({\n slug: articleSlug,\n metadata,\n filePath: indexPath,\n basePath: articlePath,\n wordCount: content.split(/\\s+/).length,\n readingTime: Math.ceil(content.split(/\\s+/).length / 200),\n })\n }\n\n return articles\n },\n }\n\n function generateRoutes(manifest: ContentManifest): Route[] {\n const routes: Route[] = [\n { path: '/', type: 'home' },\n { path: '/books', type: 'books' },\n { path: '/articles', type: 'articles' },\n ]\n\n for (const book of manifest.books) {\n routes.push({\n path: `/books/${book.slug}`,\n type: 'book',\n content: book,\n })\n\n for (const chapter of book.chapters) {\n routes.push({\n path: `/books/${book.slug}/${chapter.slug}`,\n type: 'chapter',\n content: chapter,\n book,\n })\n }\n }\n\n for (const article of manifest.articles) {\n routes.push({\n path: `/articles/${article.slug}`,\n type: 'article',\n content: article,\n })\n }\n\n return routes\n }\n\n function escapeHtmlAttr(str: string): string {\n return str.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')\n }\n\n function generateHTML(route: Route): string {\n const title = escapeHtmlAttr(getRouteTitle(route, config))\n const description = escapeHtmlAttr(getRouteDescription(route, config))\n\n let contentImport = ''\n let contentArg = ''\n let chapterMapImport = ''\n let chapterMapArg = ''\n if (route.type === 'chapter') {\n const chapter = route.content as Chapter\n const importPath = '/' + relative(root, chapter.filePath).split('\\\\').join('/')\n contentImport = `import Content from '${importPath}';\\n `\n contentArg = ', Content'\n if (route.book) {\n chapterMapImport = `import { chapterMap, chapterOrder } from '${VIRTUAL_CHAPTER_MAP_PREFIX}${route.book.slug}';\\n `\n chapterMapArg = ', { chapterMap, chapterOrder }'\n }\n } else if (route.type === 'article') {\n const article = route.content as Article\n const importPath = '/' + relative(root, article.filePath).split('\\\\').join('/')\n contentImport = `import Content from '${importPath}';\\n `\n contentArg = ', Content'\n }\n\n const dataJson = JSON.stringify({\n route: route.path,\n routeType: route.type,\n manifest,\n pagination: config.pagination,\n })\n\n const pwaTags = pwaEnabled\n ? `\n <link rel=\"manifest\" href=\"/manifest.webmanifest\">\n <meta name=\"theme-color\" content=\"${pwaConfig.themeColor}\">\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"default\">\n <meta name=\"apple-mobile-web-app-title\" content=\"${pwaConfig.shortName}\">\n <link rel=\"apple-touch-icon\" href=\"/icon-192.png\">`\n : `\n <meta name=\"theme-color\" content=\"${pwaConfig.themeColor}\">`\n\n return `<!DOCTYPE html>\n<html lang=\"${config.site.language || 'en'}\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${title}</title>\n <meta name=\"description\" content=\"${description}\">\n <link rel=\"stylesheet\" href=\"/@pressy-pub/typography/prose.css\">\n <link rel=\"stylesheet\" href=\"/@pressy-pub/typography/fluid.css\">\n <link rel=\"stylesheet\" href=\"/@pressy-pub/typography/themes/light.css\">\n <link rel=\"stylesheet\" href=\"/@pressy-pub/typography/themes/dark.css\">\n <link rel=\"stylesheet\" href=\"/@pressy-pub/typography/themes/sepia.css\">${pwaTags}\n</head>\n<body>\n <div id=\"app\"></div>\n <script type=\"module\">\n import { hydrate } from '/@pressy-pub/client';\n ${contentImport}${chapterMapImport}const data = ${dataJson};\n hydrate(data${contentArg}${chapterMapArg});\n </script>\n</body>\n</html>`\n }\n\n function getRouteTitle(route: Route, config: PressyConfig): string {\n switch (route.type) {\n case 'home':\n return config.site.title\n case 'books':\n return `Books | ${config.site.title}`\n case 'articles':\n return `Articles | ${config.site.title}`\n case 'book':\n return `${(route.content as Book).metadata.title} | ${config.site.title}`\n case 'chapter':\n return `${(route.content as Chapter).title} | ${route.book?.metadata.title} | ${config.site.title}`\n case 'article':\n return `${(route.content as Article).metadata.title} | ${config.site.title}`\n default:\n return config.site.title\n }\n }\n\n function getRouteDescription(route: Route, config: PressyConfig): string {\n switch (route.type) {\n case 'book':\n return (route.content as Book).metadata.description || ''\n case 'article':\n return (route.content as Article).metadata.description || ''\n default:\n return config.site.description || ''\n }\n }\n\n /** Generate a simple SVG icon as a placeholder when no custom icon is provided. */\n function generatePlaceholderIcon(size: number): string {\n const initial = config.site.title.charAt(0).toUpperCase()\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 ${size} ${size}\">\n <rect width=\"${size}\" height=\"${size}\" fill=\"${pwaConfig.themeColor === '#ffffff' ? '#1a1a1a' : pwaConfig.themeColor}\" rx=\"${Math.round(size * 0.15)}\"/>\n <text x=\"50%\" y=\"50%\" dominant-baseline=\"central\" text-anchor=\"middle\" font-family=\"Georgia, serif\" font-size=\"${Math.round(size * 0.45)}\" fill=\"#ffffff\">${initial}</text>\n</svg>`\n }\n\n return [\n {\n name: 'pressy:config',\n enforce: 'pre',\n async config(_, { command }) {\n if (command === 'build') {\n // Discover content early so we can set rollup inputs\n const tempContentDir = resolve(config.contentDir || 'content')\n contentDir = tempContentDir\n manifest = await contentDiscovery.discoverContent()\n routes = generateRoutes(manifest)\n\n // Create an input for each route\n const input: Record<string, string> = {\n 'pressy-entry': VIRTUAL_ENTRY_ID,\n }\n for (const route of routes) {\n const name = route.path === '/' ? 'index' : route.path.slice(1).replace(/\\//g, '-')\n input[name] = VIRTUAL_ROUTE_PREFIX + route.path\n }\n\n return {\n appType: 'custom' as const,\n resolve: {\n alias: {\n 'preact': dirname(_require.resolve('preact/package.json')),\n 'preact/jsx-runtime': dirname(_require.resolve('preact/package.json')) + '/jsx-runtime',\n },\n },\n build: {\n rollupOptions: {\n input,\n preserveEntrySignatures: 'exports-only',\n external: ['@pressy-pub/shopify'],\n },\n },\n }\n }\n return { appType: 'custom' as const }\n },\n configResolved(resolvedConfig) {\n root = resolvedConfig.root\n contentDir = resolve(root, config.contentDir || 'content')\n },\n },\n {\n name: 'pressy:content',\n async buildStart() {\n manifest = await contentDiscovery.discoverContent()\n routes = generateRoutes(manifest)\n },\n options(opts) {\n // After routes are discovered in buildStart (on subsequent builds) or\n // we set inputs here for the first build — but routes aren't ready yet.\n // We'll handle this in buildStart via emitFile instead.\n return opts\n },\n resolveId(id) {\n if (id === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_MODULE_ID\n }\n if (id === VIRTUAL_ENTRY_ID) {\n return RESOLVED_VIRTUAL_ENTRY_ID\n }\n if (id.startsWith(VIRTUAL_ROUTE_PREFIX)) {\n return '\\0' + id\n }\n if (id.startsWith(VIRTUAL_CHAPTER_MAP_PREFIX)) {\n return '\\0' + id\n }\n // @pressy-pub/shopify is optional — mark as external so Vite doesn't\n // error on the dynamic import in Paywall.tsx when shopify isn't installed\n if (id === '@pressy-pub/shopify') {\n return { id, external: true }\n }\n if (id === '/@pressy-pub/client') {\n return resolve(__dirname, '../runtime/client.js')\n }\n if (id.startsWith('/@pressy-pub/typography/')) {\n const cssFile = id.replace('/@pressy-pub/typography/', '')\n return { id: `@pressy-pub/typography/${cssFile}`, external: false }\n }\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\n return `export const manifest = ${JSON.stringify(manifest)};\nexport const routes = ${JSON.stringify(routes)};\nexport const config = ${JSON.stringify(config)};`\n }\n if (id === RESOLVED_VIRTUAL_ENTRY_ID) {\n return [\n `import '@pressy-pub/typography/prose.css'`,\n `import '@pressy-pub/typography/fluid.css'`,\n `import '@pressy-pub/typography/themes/light.css'`,\n `import '@pressy-pub/typography/themes/dark.css'`,\n `import '@pressy-pub/typography/themes/sepia.css'`,\n `export { hydrate } from '/@pressy-pub/client'`,\n ].join('\\n')\n }\n if (id.startsWith(RESOLVED_ROUTE_PREFIX)) {\n const routePath = id.slice(RESOLVED_ROUTE_PREFIX.length)\n const route = routes.find(r => r.path === routePath)\n if (!route) return null\n\n const dataJson = JSON.stringify({\n route: route.path,\n routeType: route.type,\n manifest,\n pagination: config.pagination,\n })\n\n let contentImport = ''\n let contentArg = ''\n let chapterMapImport = ''\n let chapterMapArg = ''\n if (route.type === 'chapter') {\n const chapter = route.content as Chapter\n const importPath = chapter.filePath\n contentImport = `import Content from '${importPath}';\\n`\n contentArg = ', Content'\n if (route.book) {\n chapterMapImport = `import { chapterMap, chapterOrder } from '${VIRTUAL_CHAPTER_MAP_PREFIX}${route.book.slug}';\\n`\n chapterMapArg = ', { chapterMap, chapterOrder }'\n }\n } else if (route.type === 'article') {\n const article = route.content as Article\n const importPath = article.filePath\n contentImport = `import Content from '${importPath}';\\n`\n contentArg = ', Content'\n }\n\n return [\n `import { hydrate } from '/@pressy-pub/client';`,\n contentImport,\n chapterMapImport,\n `const data = ${dataJson};`,\n `hydrate(data${contentArg}${chapterMapArg});`,\n ].join('\\n')\n }\n if (id.startsWith(RESOLVED_CHAPTER_MAP_PREFIX)) {\n const bookSlug = id.slice(RESOLVED_CHAPTER_MAP_PREFIX.length)\n const book = manifest.books.find(b => b.slug === bookSlug)\n if (!book) return null\n\n const entries = book.chapters.map(ch => {\n return ` ${JSON.stringify(ch.slug)}: () => import(${JSON.stringify(ch.filePath)})`\n })\n\n return [\n `export const chapterMap = {`,\n entries.join(',\\n'),\n `};`,\n `export const chapterOrder = ${JSON.stringify(book.chapters.map(ch => ch.slug))};`,\n ].join('\\n')\n }\n },\n },\n {\n name: 'pressy:mdx',\n async transform(code, id) {\n if (!id.endsWith('.mdx')) return null\n\n const result = await compileMDX(code, id)\n return {\n code: result.code,\n map: result.map,\n }\n },\n },\n {\n name: 'pressy:html',\n configureServer(server: ViteDevServer) {\n server.middlewares.use(async (req, res, next) => {\n const url = req.url || '/'\n\n // Suppress missing favicon requests in dev\n if (url === '/favicon.ico') {\n res.statusCode = 204\n res.end()\n return\n }\n\n // Serve a no-op service worker in dev mode so registration succeeds\n if (url === '/sw.js') {\n res.setHeader('Content-Type', 'application/javascript')\n res.setHeader('Service-Worker-Allowed', '/')\n res.end([\n '// Dev-mode service worker — no caching, passes everything through',\n 'self.addEventListener(\"install\", () => self.skipWaiting());',\n 'self.addEventListener(\"activate\", (e) => e.waitUntil(self.clients.claim()));',\n 'self.addEventListener(\"message\", (e) => {',\n ' if (e.data?.type === \"SKIP_WAITING\") self.skipWaiting();',\n '});',\n ].join('\\n'))\n return\n }\n\n // Serve a dev manifest\n if (url === '/manifest.webmanifest') {\n res.setHeader('Content-Type', 'application/manifest+json')\n res.end(JSON.stringify({\n name: config.site.title,\n short_name: pwaConfig.shortName,\n description: config.site.description,\n start_url: './',\n display: pwaConfig.display,\n background_color: pwaConfig.backgroundColor,\n theme_color: pwaConfig.themeColor,\n icons: [\n { src: './icon-192.png', sizes: '192x192', type: 'image/png' },\n { src: './icon-512.png', sizes: '512x512', type: 'image/png' },\n ],\n }, null, 2))\n return\n }\n\n // Serve placeholder icons in dev\n if (url === '/icon-192.png' || url === '/icon-512.png') {\n const size = url.includes('192') ? 192 : 512\n res.setHeader('Content-Type', 'image/svg+xml')\n res.end(generatePlaceholderIcon(size))\n return\n }\n\n // Serve offline page in dev\n if (url === '/offline.html') {\n res.setHeader('Content-Type', 'text/html')\n res.end(generateOfflinePage(config.site.title))\n return\n }\n\n // Resolve virtual /@pressy-pub/ URLs to real file paths\n if (url.startsWith('/@pressy-pub/')) {\n const bareImport = url.slice(1) // e.g. '@pressy-pub/typography/prose.css'\n try {\n const result = await server.pluginContainer.resolveId(bareImport)\n if (result && !result.external) {\n req.url = '/@fs' + result.id\n }\n } catch {}\n next()\n return\n }\n\n const pathname = url.split('?')[0]\n const route = routes.find((r) => r.path === pathname)\n\n if (route) {\n const html = generateHTML(route)\n const transformed = await server.transformIndexHtml(url, html)\n res.setHeader('Content-Type', 'text/html')\n res.end(transformed)\n return\n }\n\n next()\n })\n },\n },\n {\n name: 'pressy:build',\n apply: 'build',\n async generateBundle(_, bundle) {\n // Collect CSS files and map route names to their bundled chunks\n const cssFiles: string[] = []\n const routeChunks = new Map<string, string>() // route input name -> output fileName\n for (const [fileName, chunk] of Object.entries(bundle)) {\n if (fileName.endsWith('.css')) {\n cssFiles.push(fileName)\n }\n if (chunk.type === 'chunk' && chunk.isEntry && chunk.name) {\n routeChunks.set(chunk.name, fileName)\n }\n }\n\n // Generate HTML files for each route during build\n for (const route of routes) {\n const title = escapeHtmlAttr(getRouteTitle(route, config))\n const description = escapeHtmlAttr(getRouteDescription(route, config))\n\n // Find the bundled JS chunk for this route\n const routeName = route.path === '/' ? 'index' : route.path.slice(1).replace(/\\//g, '-')\n const routeJsFile = routeChunks.get(routeName)\n\n // Compute relative path prefix from this route's HTML back to the output root\n // e.g. \"/\" -> \"./\", \"/books/flatland\" -> \"../../\", \"/books/flatland/preface\" -> \"../../../\"\n const depth = route.path === '/' ? 0 : route.path.slice(1).split('/').length\n const assetPrefix = depth === 0 ? './' : '../'.repeat(depth)\n\n const cssLinks = cssFiles.map(f => ` <link rel=\"stylesheet\" href=\"${assetPrefix}${f}\">`).join('\\n')\n\n const buildPwaTags = pwaEnabled\n ? `\n <link rel=\"manifest\" href=\"${assetPrefix}manifest.webmanifest\">\n <meta name=\"theme-color\" content=\"${pwaConfig.themeColor}\">\n <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"default\">\n <meta name=\"apple-mobile-web-app-title\" content=\"${pwaConfig.shortName}\">\n <link rel=\"apple-touch-icon\" href=\"${assetPrefix}icon-192.png\">`\n : `\n <meta name=\"theme-color\" content=\"${pwaConfig.themeColor}\">`\n\n const html = `<!DOCTYPE html>\n<html lang=\"${config.site.language || 'en'}\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${title}</title>\n <meta name=\"description\" content=\"${description}\">\n${cssLinks}${buildPwaTags}\n</head>\n<body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"${assetPrefix}${routeJsFile}\"></script>\n</body>\n</html>`\n const fileName = route.path === '/' ? 'index.html' : `${route.path.slice(1)}/index.html`\n\n this.emitFile({\n type: 'asset',\n fileName,\n source: html,\n })\n }\n\n // Generate manifest.webmanifest\n const hasCustomIcons = config.pwa?.icon192 && config.pwa?.icon512\n\n const webManifest = {\n name: config.site.title,\n short_name: pwaConfig.shortName,\n description: config.site.description,\n start_url: './',\n display: pwaConfig.display,\n background_color: pwaConfig.backgroundColor,\n theme_color: pwaConfig.themeColor,\n icons: [\n {\n src: './icon-192.png',\n sizes: '192x192',\n type: 'image/png',\n },\n {\n src: './icon-512.png',\n sizes: '512x512',\n type: 'image/png',\n purpose: 'any maskable',\n },\n ],\n }\n\n this.emitFile({\n type: 'asset',\n fileName: 'manifest.webmanifest',\n source: JSON.stringify(webManifest, null, 2),\n })\n\n // Emit offline fallback page\n this.emitFile({\n type: 'asset',\n fileName: 'offline.html',\n source: generateOfflinePage(config.site.title),\n })\n\n // Emit placeholder SVG icons if no custom icons provided\n if (!hasCustomIcons) {\n this.emitFile({\n type: 'asset',\n fileName: 'icon-192.png',\n source: generatePlaceholderIcon(192),\n })\n this.emitFile({\n type: 'asset',\n fileName: 'icon-512.png',\n source: generatePlaceholderIcon(512),\n })\n }\n\n // Build service worker with precache manifest\n if (pwaEnabled) {\n const precacheEntries: Array<{ url: string; revision: string | null }> = []\n\n // Use relative URLs so precaching works on subpath deployments\n // (e.g. /pressy/ or /pressy/pr-preview/pr-1/)\n // The SW resolves these relative to its own scope.\n\n // Helper: generate a short content hash for revision tracking.\n // Files with hashed names (JS/CSS chunks) use revision: null since\n // the hash is in the URL. Non-hashed files (HTML) need an explicit\n // revision so workbox knows when to update them.\n const contentRevision = (source: string) =>\n createHash('md5').update(source).digest('hex').slice(0, 8)\n\n // Add all HTML pages (non-hashed filenames → need revision)\n for (const route of routes) {\n const fileName = route.path === '/' ? 'index.html' : `${route.path.slice(1)}/index.html`\n const htmlAsset = bundle[fileName]\n const source = htmlAsset && htmlAsset.type === 'asset' ? String(htmlAsset.source) : ''\n precacheEntries.push({\n url: `./${fileName}`,\n revision: contentRevision(source),\n })\n }\n\n // Add offline page (non-hashed → need revision)\n const offlineSource = generateOfflinePage(config.site.title)\n precacheEntries.push({ url: './offline.html', revision: contentRevision(offlineSource) })\n\n // Add built JS/CSS chunks (hashed filenames → revision: null)\n for (const [fileName] of Object.entries(bundle)) {\n if (fileName.endsWith('.js') || fileName.endsWith('.css')) {\n precacheEntries.push({\n url: `./${fileName}`,\n revision: null,\n })\n }\n }\n\n // Bundle the service worker into a self-contained IIFE using esbuild\n // so that workbox imports are inlined (service workers can't use ES module imports)\n const swSourcePath = resolve(__dirname, '../runtime/sw.js')\n const manifestJson = JSON.stringify(precacheEntries)\n const { build: esbuildBuild } = await import('esbuild')\n const esbuildResult = await esbuildBuild({\n entryPoints: [swSourcePath],\n bundle: true,\n format: 'iife',\n write: false,\n platform: 'browser',\n define: {\n 'self.__WB_MANIFEST': manifestJson,\n },\n })\n const swCode = esbuildResult.outputFiles![0].text\n\n this.emitFile({\n type: 'asset',\n fileName: 'sw.js',\n source: swCode,\n })\n }\n },\n },\n ]\n}\n","import { compile } from '@mdx-js/mdx'\nimport remarkGfm from 'remark-gfm'\nimport rehypeSlug from 'rehype-slug'\n\nimport matter from 'gray-matter'\n\nexport interface MDXCompileResult {\n code: string\n map: string | null\n frontmatter: Record<string, unknown>\n}\n\nexport async function compileMDX(\n source: string,\n filePath: string\n): Promise<MDXCompileResult> {\n // Extract frontmatter\n const { content, data: frontmatter } = matter(source)\n\n // Compile MDX — jsx: false outputs valid JS with _jsx() calls\n const result = await compile(content, {\n jsxImportSource: 'preact',\n remarkPlugins: [remarkGfm],\n rehypePlugins: [rehypeSlug],\n development: false,\n })\n\n // With jsx: false (default), the compiled output is valid JS\n // with its own JSX runtime imports and default export.\n // We just append the frontmatter as a named export.\n const compiled = String(result)\n const code = `${compiled}\nexport const frontmatter = ${JSON.stringify(frontmatter)};\n`\n\n return {\n code,\n map: null,\n frontmatter,\n }\n}\n\n// Helper to extract table of contents from MDX\nexport function extractTableOfContents(source: string): Array<{\n level: number\n text: string\n slug: string\n}> {\n const headingRegex = /^(#{1,6})\\s+(.+)$/gm\n const toc: Array<{ level: number; text: string; slug: string }> = []\n let match\n\n while ((match = headingRegex.exec(source)) !== null) {\n const level = match[1].length\n const text = match[2].trim()\n const slug = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '')\n\n toc.push({ level, text, slug })\n }\n\n return toc\n}\n\n// Calculate reading time\nexport function calculateReadingTime(content: string): number {\n const wordsPerMinute = 200\n const words = content.trim().split(/\\s+/).length\n return Math.ceil(words / wordsPerMinute)\n}\n","/** Generates the offline fallback HTML page. */\nexport function generateOfflinePage(siteTitle: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Offline | ${siteTitle}</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n font-family: Georgia, 'Times New Roman', serif;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n padding: 2rem;\n background: #fafafa;\n color: #1a1a1a;\n }\n\n .offline-container {\n text-align: center;\n max-width: 420px;\n }\n\n .offline-icon {\n width: 64px;\n height: 64px;\n margin: 0 auto 1.5rem;\n color: #999;\n }\n\n h1 {\n font-size: 1.5rem;\n margin-bottom: 0.75rem;\n }\n\n p {\n color: #666;\n line-height: 1.6;\n margin-bottom: 1.5rem;\n }\n\n button {\n font-family: inherit;\n font-size: 1rem;\n padding: 0.75rem 1.5rem;\n background: #1a1a1a;\n color: #fff;\n border: none;\n border-radius: 0.5rem;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n button:hover { background: #333; }\n\n @media (prefers-color-scheme: dark) {\n body { background: #1a1a1a; color: #e5e5e5; }\n p { color: #999; }\n .offline-icon { color: #666; }\n button { background: #e5e5e5; color: #1a1a1a; }\n button:hover { background: #ccc; }\n }\n </style>\n</head>\n<body>\n <div class=\"offline-container\">\n <svg class=\"offline-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M23.64 7c-.45-.34-4.93-4-11.64-4-1.5 0-2.89.19-4.15.48L18.18 13.8 23.64 7zM3.41 1.31L2 2.72l2.05 2.05C1.91 5.76.59 6.82.36 7L12 21.5l3.91-4.87 3.32 3.32 1.41-1.41L3.41 1.31z\"/>\n </svg>\n <h1>You\\u2019re offline</h1>\n <p>This page isn\\u2019t available right now. If you\\u2019ve previously downloaded this book for offline reading, try navigating to it directly.</p>\n <button onclick=\"window.location.reload()\">Try again</button>\n </div>\n</body>\n</html>`\n}\n"],"mappings":"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","names":["matter","matter","content","manifest","routes","config"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as _preact_signals from '@preact/signals';
|
|
2
|
+
export { effect, signal } from '@preact/signals';
|
|
3
|
+
import { ComponentType } from 'preact';
|
|
4
|
+
import { R as ReadingProgress, b as ContentManifest, c as ChapterMapData } from '../types-CQs_xIit.js';
|
|
5
|
+
import { a as PaginationConfig } from '../config-DlVehy4M.js';
|
|
6
|
+
|
|
7
|
+
declare const currentRoute: _preact_signals.Signal<string>;
|
|
8
|
+
declare const currentTheme: _preact_signals.Signal<"light" | "dark" | "sepia" | "system">;
|
|
9
|
+
declare const isOffline: _preact_signals.Signal<boolean>;
|
|
10
|
+
declare function saveReadingProgress(progress: ReadingProgress): Promise<void>;
|
|
11
|
+
declare function getReadingProgress(chapterSlug: string): Promise<ReadingProgress | null>;
|
|
12
|
+
declare function getAllReadingProgress(): Promise<ReadingProgress[]>;
|
|
13
|
+
declare function isBookUnlocked(bookSlug: string): Promise<boolean>;
|
|
14
|
+
declare function unlockBook(bookSlug: string, orderId?: string): Promise<void>;
|
|
15
|
+
declare function navigate(path: string, replace?: boolean): void;
|
|
16
|
+
declare function setTheme(theme: 'light' | 'dark' | 'sepia' | 'system'): void;
|
|
17
|
+
interface HydrateData {
|
|
18
|
+
route: string;
|
|
19
|
+
routeType: string;
|
|
20
|
+
manifest: ContentManifest;
|
|
21
|
+
pagination?: PaginationConfig;
|
|
22
|
+
}
|
|
23
|
+
declare function hydrate(data: HydrateData, Content?: ComponentType, chapterMapData?: ChapterMapData): void;
|
|
24
|
+
|
|
25
|
+
export { currentRoute, currentTheme, getAllReadingProgress, getReadingProgress, hydrate, isBookUnlocked, isOffline, navigate, saveReadingProgress, setTheme, unlockBook };
|