0x1
Version:
318 lines (284 loc) • 20.4 kB
JavaScript
var{existsSync:N}=(()=>({}));var{create:Q,defineProperty:B,getOwnPropertyDescriptor:U,getOwnPropertyNames:X,getPrototypeOf:Y}=Object,Z=Object.prototype.hasOwnProperty,$=(u,s)=>()=>(s||u((s={exports:{}}).exports,s),s.exports),M=(u,s,d,m)=>{if(s&&typeof s=="object"||typeof s=="function")for(let x of X(s))!Z.call(u,x)&&x!==d&&B(u,x,{get:()=>s[x],enumerable:!(m=U(s,x))||m.enumerable});return u},W=(u,s,d)=>(d=u!=null?Q(Y(u)):{},M(s||!u||!u.__esModule?B(d,"default",{value:u,enumerable:!0}):d,u)),a=$((u,s)=>{function d(e){if(typeof e!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(e))}function m(e,t){for(var r="",b=0,h=-1,l=0,A,v=0;v<=e.length;++v){if(v<e.length)A=e.charCodeAt(v);else{if(A===47)break;A=47}if(A===47){if(!(h===v-1||l===1))if(h!==v-1&&l===2){if(r.length<2||b!==2||r.charCodeAt(r.length-1)!==46||r.charCodeAt(r.length-2)!==46){if(r.length>2){var z=r.lastIndexOf("/");if(z!==r.length-1){z===-1?(r="",b=0):(r=r.slice(0,z),b=r.length-1-r.lastIndexOf("/")),h=v,l=0;continue}}else if(r.length===2||r.length===1){r="",b=0,h=v,l=0;continue}}t&&(r.length>0?r+="/..":r="..",b=2)}else r.length>0?r+="/"+e.slice(h+1,v):r=e.slice(h+1,v),b=v-h-1;h=v,l=0}else A===46&&l!==-1?++l:l=-1}return r}function x(e,t){var r=t.dir||t.root,b=t.base||(t.name||"")+(t.ext||"");return r?r===t.root?r+b:r+e+b:b}var y={resolve:function(){for(var e="",t=!1,r,b=arguments.length-1;b>=-1&&!t;b--){var h;b>=0?h=arguments[b]:(r===void 0&&(r=process.cwd()),h=r),d(h),h.length!==0&&(e=h+"/"+e,t=h.charCodeAt(0)===47)}return e=m(e,!t),t?e.length>0?"/"+e:"/":e.length>0?e:"."},normalize:function(e){if(d(e),e.length===0)return".";var t=e.charCodeAt(0)===47,r=e.charCodeAt(e.length-1)===47;return e=m(e,!t),e.length===0&&!t&&(e="."),e.length>0&&r&&(e+="/"),t?"/"+e:e},isAbsolute:function(e){return d(e),e.length>0&&e.charCodeAt(0)===47},join:function(){if(arguments.length===0)return".";for(var e,t=0;t<arguments.length;++t){var r=arguments[t];d(r),r.length>0&&(e===void 0?e=r:e+="/"+r)}return e===void 0?".":y.normalize(e)},relative:function(e,t){if(d(e),d(t),e===t||(e=y.resolve(e),t=y.resolve(t),e===t))return"";for(var r=1;r<e.length&&e.charCodeAt(r)===47;++r);for(var b=e.length,h=b-r,l=1;l<t.length&&t.charCodeAt(l)===47;++l);for(var A=t.length,v=A-l,z=h<v?h:v,_=-1,O=0;O<=z;++O){if(O===z){if(v>z){if(t.charCodeAt(l+O)===47)return t.slice(l+O+1);if(O===0)return t.slice(l+O)}else h>z&&(e.charCodeAt(r+O)===47?_=O:O===0&&(_=0));break}var D=e.charCodeAt(r+O),K=t.charCodeAt(l+O);if(D!==K)break;D===47&&(_=O)}var T="";for(O=r+_+1;O<=b;++O)(O===b||e.charCodeAt(O)===47)&&(T.length===0?T+="..":T+="/..");return T.length>0?T+t.slice(l+_):(l+=_,t.charCodeAt(l)===47&&++l,t.slice(l))},_makeLong:function(e){return e},dirname:function(e){if(d(e),e.length===0)return".";for(var t=e.charCodeAt(0),r=t===47,b=-1,h=!0,l=e.length-1;l>=1;--l)if(t=e.charCodeAt(l),t===47){if(!h){b=l;break}}else h=!1;return b===-1?r?"/":".":r&&b===1?"//":e.slice(0,b)},basename:function(e,t){if(t!==void 0&&typeof t!="string")throw new TypeError('"ext" argument must be a string');d(e);var r=0,b=-1,h=!0,l;if(t!==void 0&&t.length>0&&t.length<=e.length){if(t.length===e.length&&t===e)return"";var A=t.length-1,v=-1;for(l=e.length-1;l>=0;--l){var z=e.charCodeAt(l);if(z===47){if(!h){r=l+1;break}}else v===-1&&(h=!1,v=l+1),A>=0&&(z===t.charCodeAt(A)?--A===-1&&(b=l):(A=-1,b=v))}return r===b?b=v:b===-1&&(b=e.length),e.slice(r,b)}else{for(l=e.length-1;l>=0;--l)if(e.charCodeAt(l)===47){if(!h){r=l+1;break}}else b===-1&&(h=!1,b=l+1);return b===-1?"":e.slice(r,b)}},extname:function(e){d(e);for(var t=-1,r=0,b=-1,h=!0,l=0,A=e.length-1;A>=0;--A){var v=e.charCodeAt(A);if(v===47){if(!h){r=A+1;break}continue}b===-1&&(h=!1,b=A+1),v===46?t===-1?t=A:l!==1&&(l=1):t!==-1&&(l=-1)}return t===-1||b===-1||l===0||l===1&&t===b-1&&t===r+1?"":e.slice(t,b)},format:function(e){if(e===null||typeof e!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof e);return x("/",e)},parse:function(e){d(e);var t={root:"",dir:"",base:"",ext:"",name:""};if(e.length===0)return t;var r=e.charCodeAt(0),b=r===47,h;b?(t.root="/",h=1):h=0;for(var l=-1,A=0,v=-1,z=!0,_=e.length-1,O=0;_>=h;--_){if(r=e.charCodeAt(_),r===47){if(!z){A=_+1;break}continue}v===-1&&(z=!1,v=_+1),r===46?l===-1?l=_:O!==1&&(O=1):l!==-1&&(O=-1)}return l===-1||v===-1||O===0||O===1&&l===v-1&&l===A+1?v!==-1&&(A===0&&b?t.base=t.name=e.slice(1,v):t.base=t.name=e.slice(A,v)):(A===0&&b?(t.name=e.slice(1,l),t.base=e.slice(1,v)):(t.name=e.slice(A,l),t.base=e.slice(A,v)),t.ext=e.slice(l,v)),A>0?t.dir=e.slice(0,A-1):b&&(t.dir="/"),t},sep:"/",delimiter:":",win32:null,posix:null};y.posix=y,s.exports=y}),G=W(a()),k=G,L=G,J=function(u){return u},H=function(){throw new Error("Not implemented")};k.parse??=H;L.parse??=H;var R={resolve:k.resolve.bind(k),normalize:k.normalize.bind(k),isAbsolute:k.isAbsolute.bind(k),join:k.join.bind(k),relative:k.relative.bind(k),toNamespacedPath:J,dirname:k.dirname.bind(k),basename:k.basename.bind(k),extname:k.extname.bind(k),format:k.format.bind(k),parse:k.parse.bind(k),sep:"/",delimiter:":",win32:void 0,posix:void 0,_makeLong:J},q={sep:"\\",delimiter:";",win32:void 0,...R,posix:R};R.win32=q.win32=q;R.posix=R;var{resolve:F,normalize:C,isAbsolute:n,join:E,relative:i,toNamespacedPath:P,dirname:p,basename:f,extname:g,format:c,parse:o,sep:ee,delimiter:re}=R;function j(u){try{let s=u.app?.pwa||{},d=u.pwa||{},m=u.app||{};if(!(d.enabled!==!1&&(s.name||m.name||d.enabled===!0)))return null;return{name:s.name||m.name||m.title||"0x1 App",shortName:s.shortName||V(s.name||m.name||m.title||"0x1"),description:s.description||m.description||"Built with 0x1 - the ultra-minimal framework",themeColor:s.themeColor||"#7c3aed",backgroundColor:s.backgroundColor||"#ffffff",display:s.display||"standalone",statusBarStyle:s.statusBarStyle||"default",startUrl:s.startUrl||"/",orientation:s.orientation||"any",scope:s.scope||"/",iconsPath:s.iconsPath||"/icons",generateIcons:s.generateIcons!==!1,offlineSupport:s.offlineSupport!==!1,cacheStrategy:s.cacheStrategy||"stale-while-revalidate",cacheName:s.cacheName||I(m.name||"0x1-app"),precacheResources:S(s.precacheResources,["/","/index.html","/styles.css","/app.js","/icons/favicon.svg"]),enabled:d.enabled!==!1,manifest:d.manifest||"/manifest.json",workbox:d.workbox,icons:d.icons}}catch(s){return console.warn(`[PWA Config Parser] Error parsing complex config: ${s}`),null}}function V(u){let s=u.split(/[^a-zA-Z0-9]/).filter(Boolean);if(s.length>1)return s.slice(0,4).map((d)=>d.charAt(0).toUpperCase()).join("");else return u.substring(0,Math.min(8,u.length))}function I(u){return`${u.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}-cache-v1`}function S(u,s){let d=[...u||[],...s||[]];return[...new Set(d)]}async function le(u){let s=[u,"0x1.config.ts","0x1.config.js","ox1.config.ts","ox1.config.js"].filter(Boolean);for(let d of s)try{if(!await Bun.file(d).exists())continue;let x=await Bun.file(d).text(),y=w(x);if(y){let e=j(y);if(e)return e}}catch(m){console.warn(`[PWA] Could not load config from ${d}: ${m}`);continue}return null}function w(u){try{let d=u.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"").replace(/import\s+.*?from\s+.*?;/g,"").replace(/export\s+type\s+.*?;/g,"").match(/export\s+default\s+(\{[\s\S]*?\});?\s*$/m);if(!d)return console.warn("[PWA Config Parser] No default export found"),null;let m=d[1];return m=m.replace(/process\.env\.(\w+)/g,(e,t)=>{let r=process.env[t];return r?`"${r}"`:"undefined"}).replace(/process\.env\.(\w+)\s*===\s*["']([^"']+)["']/g,(e,t,r)=>{return process.env[t]===r?"true":"false"}),new Function("console",`
// Provide safe console object
const process = { env: ${JSON.stringify(process.env)} };
// Return the config object
return ${m};
`)(console)}catch(s){return console.warn(`[PWA Config Parser] Failed to parse config: ${s}`),null}}var be={name:"0x1 App",shortName:"0x1",description:"Built with 0x1 - the ultra-minimal framework",themeColor:"#7c3aed",backgroundColor:"#ffffff",display:"standalone",startUrl:"/",orientation:"any",iconsPath:"/icons",generateIcons:!0,offlineSupport:!0,cacheStrategy:"stale-while-revalidate",cacheName:"0x1-cache-v1",statusBarStyle:"default",precacheResources:["/","/index.html","/styles.css","/app.js"]};function de(u,s){let d=u.iconsPath||"/icons",m=[{size:"48x48",purpose:"any"},{size:"72x72",purpose:"any"},{size:"96x96",purpose:"any"},{size:"144x144",purpose:"any"},{size:"192x192",purpose:"any"},{size:"512x512",purpose:"any"},{size:"192x192",purpose:"maskable"},{size:"512x512",purpose:"maskable"}],x=[],y=(r)=>{if(!s)return u.generateIcons!==!1;return[E(s,"public","icons",r),E(s,"icons",r),E(s,"assets","icons",r),E(s,"static","icons",r),E(s,"dist","icons",r),E(s,"build","icons",r)].some((h)=>N(h))};for(let r of m){let b=r.purpose==="maskable"?`maskable-icon-${r.size}.png`:`icon-${r.size}.png`;if(y(b))x.push({src:`${d}/${b}`,sizes:r.size,type:"image/png",purpose:r.purpose})}let e=["icon.svg","icon-512x512.svg"];for(let r of e)if(y(r))x.push({src:`${d}/${r}`,sizes:r==="icon.svg"?"any":"512x512",type:"image/svg+xml",purpose:"any"});if(x.length===0&&u.generateIcons!==!1){let r=[{src:`${d}/icon-192x192.png`,sizes:"192x192",type:"image/png",purpose:"any"},{src:`${d}/icon-512x512.png`,sizes:"512x512",type:"image/png",purpose:"any"}];x.push(...r)}let t={name:u.name,short_name:u.shortName,description:u.description,start_url:u.startUrl||"/",display:u.display,background_color:u.backgroundColor,theme_color:u.themeColor,orientation:u.orientation||"any",icons:x,screenshots:[],id:u.name.toLowerCase().replace(/\s+/g,"-"),dir:"ltr",lang:"en-US",categories:["productivity"],scope:u.scope||"/",prefer_related_applications:!1,shortcuts:[{name:"Home",url:"/",description:"Go to the home page",icons:x.length>0?[{src:`${d}/icon-192x192.png`,sizes:"192x192",type:"image/png"}]:[]}],file_handlers:[],handle_links:"preferred",launch_handler:{client_mode:["navigate-existing","auto"]},display_override:["window-controls-overlay",u.display||"standalone"]};return JSON.stringify(t,null,2)}function he(u){let s=u.cacheName||"0x1-cache-v1",d=JSON.stringify(u.precacheResources||[]),m=u.cacheStrategy||"stale-while-revalidate",x;switch(m){case"cache-first":x=`
async function fetchResource(request) {
// Try cache first, then network
const cachedResponse = await caches.match(request);
if (cachedResponse) return cachedResponse;
// If not in cache, fetch from network
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, networkResponse.clone());
}
return networkResponse;
} catch (error) {
return new Response('Network error', { status: 408 });
}
}`;break;case"network-first":x=`
async function fetchResource(request) {
// Try network first, then cache
try {
const networkResponse = await fetch(request);
if (networkResponse.ok) {
const cache = await caches.open(CACHE_NAME);
cache.put(request, networkResponse.clone());
}
return networkResponse;
} catch (error) {
// If network fails, use cache
const cachedResponse = await caches.match(request);
return cachedResponse || new Response('Network error', { status: 408 });
}
}`;break;case"stale-while-revalidate":default:x=`
async function fetchResource(request) {
// Return cached version immediately (if available)
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await caches.match(request);
// Update cache in background
const fetchPromise = fetch(request).then(networkResponse => {
if (networkResponse.ok) {
cache.put(request, networkResponse.clone());
}
return networkResponse;
}).catch(() => null);
// Return cached version or wait for network
return cachedResponse || fetchPromise;
}`;break}return`// 0x1 Service Worker
// Generated on ${new Date().toISOString()}
const CACHE_NAME = '${s}';
const OFFLINE_URL = '/offline.html';
const PRECACHE_RESOURCES = ${d};
// CRITICAL FIX: Validate resources before caching to prevent addAll failures
async function validateAndCacheResources(cache, resources) {
const validResources = [];
for (const url of resources) {
try {
const response = await fetch(url);
if (response.ok) {
validResources.push(url);
await cache.put(url, response);
/* console.log removed */
} else {
console.warn('[SW] Resource not found, skipping cache:', url, response.status);
}
} catch (error) {
console.warn('[SW] Failed to fetch resource, skipping cache:', url, error.message);
}
}
/* console.log removed */
return validResources;
}
// Install event - precache resources with validation
self.addEventListener('install', (event) => {
event.waitUntil(
(async () => {
try {
const cache = await caches.open(CACHE_NAME);
// CRITICAL FIX: Validate resources before attempting to cache them
await validateAndCacheResources(cache, PRECACHE_RESOURCES);
await self.skipWaiting();
/* console.log removed */
} catch (error) {
console.error('[SW] Installation failed:', error);
// Still complete installation even if caching fails
await self.skipWaiting();
}
})()
);
});
// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.filter((name) => {
return name !== CACHE_NAME;
}).map((name) => {
return caches.delete(name);
})
);
}).then(() => {
return self.clients.claim();
})
);
});
// Fetch event - respond with cache or network
${x}
self.addEventListener('fetch', (event) => {
// Skip cross-origin requests
if (!event.request.url.startsWith(self.location.origin)) {
return;
}
// Handle navigation requests
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => {
return caches.match(OFFLINE_URL) ||
caches.match('/') ||
new Response('You are offline', { headers: { 'Content-Type': 'text/html' }});
})
);
return;
}
// Handle other requests with chosen strategy
event.respondWith(fetchResource(event.request));
});
// Handle push notifications
self.addEventListener('push', (event) => {
if (!event.data) return;
const data = event.data.json();
const options = {
body: data.body,
icon: '${u.iconsPath||"/icons"}/icon-192x192.png',
badge: '${u.iconsPath||"/icons"}/badge-96x96.png',
vibrate: [100, 50, 100],
data: {
url: data.url || '/'
}
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});
// Handle notification clicks
self.addEventListener('notificationclick', (event) => {
event.notification.close();
event.waitUntil(
clients.matchAll({type: 'window'}).then((clientList) => {
for (const client of clientList) {
if ('focus' in client) return client.focus();
}
if (clients.openWindow) {
return clients.openWindow(event.notification.data.url);
}
})
);
});
// Periodic sync for background updates
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
async function syncContent() {
// Sync content in background when online
if (navigator.onLine) {
try {
const cache = await caches.open(CACHE_NAME);
// Update precached resources with validation
await validateAndCacheResources(cache, PRECACHE_RESOURCES);
} catch (error) {
console.error('Background sync failed:', error);
}
}
}
`}function ve(){return`// Service Worker Registration
if ('serviceWorker' in navigator) {
window.addEventListener('load', async () => {
try {
const registration = await navigator.serviceWorker.register('/service-worker.js', {
scope: '/'
});
/* console.log removed */
// Setup periodic background sync if supported
if ('periodicSync' in registration) {
try {
await registration.periodicSync.register('content-sync', {
minInterval: 24 * 60 * 60 * 1000 // Once per day
});
} catch (error) {
/* console.log removed */
}
}
// Register for push notifications
if ('PushManager' in window) {
// The pushManager property interface allows you to receive notifications from third-party servers
const subscribed = await registration.pushManager.getSubscription();
if (!subscribed) {
/* console.log removed */
}
}
} catch (error) {
console.error('ServiceWorker registration failed:', error);
}
});
}`}function Ae(u){return`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Offline | ${u.name}</title>
<meta name="theme-color" content="${u.themeColor}">
<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: ${u.backgroundColor};
color: #333;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 1rem;
text-align: center;
}
.offline-container {
max-width: 500px;
padding: 2rem;
background-color: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
h1 {
margin-bottom: 1rem;
color: ${u.themeColor};
}
p {
margin-bottom: 1.5rem;
line-height: 1.6;
}
.icon {
margin-bottom: 2rem;
width: 80px;
height: 80px;
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: ${u.themeColor};
color: white;
text-decoration: none;
border-radius: 4px;
font-weight: 500;
}
</style>
</head>
<body>
<div class="offline-container">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="${u.themeColor}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="1" y1="1" x2="23" y2="23"></line>
<path d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"></path>
<path d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39"></path>
<path d="M10.71 5.05A16 16 0 0 1 22.58 9"></path>
<path d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88"></path>
<path d="M8.53 16.11a6 6 0 0 1 6.95 0"></path>
<line x1="12" y1="20" x2="12.01" y2="20"></line>
</svg>
<h1>You're Offline</h1>
<p>It looks like you're currently offline. Please check your internet connection and try again.</p>
<button class="btn" onclick="window.location.reload()">Retry</button>
</div>
</body>
</html>`}function me(u){}function Oe(u){return{title:u.name,description:u.description,themeColor:u.themeColor,manifest:"/manifest.json",viewport:{width:"device-width",initialScale:1,themeColor:u.themeColor},appleWebApp:{capable:!0,title:u.shortName||u.name,statusBarStyle:u.statusBarStyle||"default"},icons:{icon:[{url:"/icons/icon-192x192.png",sizes:"192x192",type:"image/png"},{url:"/icons/icon-512x512.png",sizes:"512x512",type:"image/png"}],apple:[{url:"/icons/apple-touch-icon.png",sizes:"180x180",type:"image/png"}]}}}export{me as registerPWA,Oe as pwaConfigToMetadata,j as parseComplexPWAConfig,le as loadPWAConfig,ve as generateServiceWorkerRegistration,he as generateServiceWorker,Ae as generateOfflinePage,de as generateManifest,be as DEFAULT_PWA_CONFIG};