diff --git a/demo-static/astro.config.mjs b/demo-static/astro.config.mjs
new file mode 100644
index 0000000..98d511d
--- /dev/null
+++ b/demo-static/astro.config.mjs
@@ -0,0 +1,36 @@
+// @ts-check
+
+import { defineConfig } from 'astro/config'
+import serviceWorker from '@ayco/astro-sw'
+// import { deleteOldCaches, staleWhileRevalidate } from '@ayco/astro-sw/presets'
+
+import * as pkg from './package.json'
+
+export default defineConfig({
+ output: 'static',
+ site: 'https://ayo.ayco.io',
+ integrations: [
+ serviceWorker({
+ path: './src/sw.ts',
+ assetCachePrefix: 'AstroSWTest',
+ assetCacheVersionID: pkg.version,
+ // presets: [staleWhileRevalidate(), deleteOldCaches()],
+ exclude: ['/exclude'],
+ // include: ['/components/web-component.js'],
+ logAssets: true,
+ esbuild: {
+ minify: true,
+ },
+ registrationHooks: {
+ installing: () => console.log('>>> installing...'),
+ waiting: () => console.log('>>> waiting...'),
+ active: () => console.log('>>> active...'),
+ error: (error) => console.error('>>> error', error),
+ afterRegistration: async () => {
+ const sw = await navigator.serviceWorker.getRegistration()
+ console.log('>>> registrered', sw)
+ },
+ },
+ }),
+ ],
+})
diff --git a/demo-static/package.json b/demo-static/package.json
new file mode 100644
index 0000000..8a2a31f
--- /dev/null
+++ b/demo-static/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "demo-static",
+ "private": true,
+ "version": "1.0.3",
+ "main": "index.js",
+ "scripts": {
+ "start": "astro dev",
+ "dev": "astro dev",
+ "build": "astro build",
+ "build:preview:static": "astro build && astro preview",
+ "build:preview": "astro build && astro preview"
+ },
+ "author": "Ayo Ayco",
+ "license": "MIT",
+ "description": "",
+ "devDependencies": {
+ "@astrojs/node": "^10.0.4",
+ "@ayco/astro-sw": "workspace:*",
+ "@fastify/middie": "^9.3.1",
+ "@fastify/static": "^9.0.0",
+ "astro": "^6.1.3",
+ "fastify": "^5.8.4"
+ }
+}
diff --git a/demo-static/public/Thanos.jpg b/demo-static/public/Thanos.jpg
new file mode 100644
index 0000000..e6b48fe
Binary files /dev/null and b/demo-static/public/Thanos.jpg differ
diff --git a/demo-static/public/components/web-component.js b/demo-static/public/components/web-component.js
new file mode 100644
index 0000000..cb5d505
--- /dev/null
+++ b/demo-static/public/components/web-component.js
@@ -0,0 +1,14 @@
+function register(){
+ if ('customElements' in window)
+ window.customElements.define('web-component', WebComponent)
+}
+
+class WebComponent extends HTMLElement {
+ connectedCallback() {
+ console.log('hello')
+ }
+}
+
+register()
+
+export default WebComponent
\ No newline at end of file
diff --git a/demo-static/public/favicon.ico b/demo-static/public/favicon.ico
new file mode 100644
index 0000000..3afdf7c
Binary files /dev/null and b/demo-static/public/favicon.ico differ
diff --git a/demo-static/public/sample.asset.txt b/demo-static/public/sample.asset.txt
new file mode 100644
index 0000000..a95e94f
--- /dev/null
+++ b/demo-static/public/sample.asset.txt
@@ -0,0 +1 @@
+asset
\ No newline at end of file
diff --git a/demo-static/src/env.d.ts b/demo-static/src/env.d.ts
new file mode 100644
index 0000000..acef35f
--- /dev/null
+++ b/demo-static/src/env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/demo-static/src/pages/404.astro b/demo-static/src/pages/404.astro
new file mode 100644
index 0000000..c08259f
--- /dev/null
+++ b/demo-static/src/pages/404.astro
@@ -0,0 +1,5 @@
+---
+
+---
+
+404
diff --git a/demo-static/src/pages/blog/[...slug].astro b/demo-static/src/pages/blog/[...slug].astro
new file mode 100644
index 0000000..e164c8c
--- /dev/null
+++ b/demo-static/src/pages/blog/[...slug].astro
@@ -0,0 +1,17 @@
+---
+import { type CollectionEntry, getCollection } from 'astro:content'
+
+export async function getStaticPaths() {
+ const posts = await getCollection('blog')
+ return posts.map((post) => ({
+ params: { slug: post.slug },
+ props: post,
+ }))
+}
+type Props = CollectionEntry<'blog'>
+
+const post = Astro.props
+const { Content } = await post.render()
+---
+
+
diff --git a/demo-static/src/pages/blog/index.astro b/demo-static/src/pages/blog/index.astro
new file mode 100644
index 0000000..d41545b
--- /dev/null
+++ b/demo-static/src/pages/blog/index.astro
@@ -0,0 +1,7 @@
+---
+
+---
+
+blog index
+
+post
diff --git a/demo-static/src/pages/exclude.astro b/demo-static/src/pages/exclude.astro
new file mode 100644
index 0000000..1b491ff
--- /dev/null
+++ b/demo-static/src/pages/exclude.astro
@@ -0,0 +1,5 @@
+---
+
+---
+
+exclude
diff --git a/demo-static/src/pages/index.astro b/demo-static/src/pages/index.astro
new file mode 100644
index 0000000..93d3550
--- /dev/null
+++ b/demo-static/src/pages/index.astro
@@ -0,0 +1,15 @@
+---
+// export const prerender = false
+---
+
+
+
+
+
+
+ Hello
+
+
+ Hello
+
+
diff --git a/demo-static/src/sw.ts b/demo-static/src/sw.ts
new file mode 100644
index 0000000..028d25d
--- /dev/null
+++ b/demo-static/src/sw.ts
@@ -0,0 +1,135 @@
+/**
+ * Note: @ayco/astro-sw integration injects variables `__prefix`, `__version`, & `__assets`
+ * -- find usage in `astro.config.mjs` integrations
+ * @see https://ayco.io/n/@ayco/astro-sw
+ */
+const cacheName = `${__prefix ?? 'app'}-v${__version ?? '000'}`
+const forceLogging = true
+
+/**
+ * Cleans up old service worker caches by deleting any cache that doesn't match the current cache name.
+ * This ensures only the current version of the application's cache is retained.
+ * @async
+ * @function cleanOldCaches
+ * @returns {Promise} A promise that resolves when old caches have been deleted
+ */
+const cleanOldCaches = async () => {
+ const allowCacheNames = [cacheName]
+ const allCaches = await caches.keys()
+ allCaches.forEach((key) => {
+ if (!allowCacheNames.includes(key)) {
+ console.info('Deleting old cache', key)
+ caches
+ .delete(key)
+ .then(() => {
+ console.info('Successfully deleted cache:', key)
+ })
+ .catch((error) => {
+ console.warn('Failed to delete old cache:', key, error)
+ })
+ }
+ })
+}
+
+/**
+ * Adds specified resources to the service worker cache.
+ * This function is used to cache static assets for offline access.
+ * @async
+ * @function addResourcesToCache
+ * @param {Array} resources - An array of URLs representing the resources to be cached.
+ * @returns {Promise} A promise that resolves when all resources have been successfully added to the cache.
+ */
+const addResourcesToCache = async (resources) => {
+ const cache = await caches.open(cacheName)
+ console.info('adding resources to cache...', {
+ force: !!forceLogging,
+ context: 'ayco-sw',
+ data: resources,
+ })
+ try {
+ await cache.addAll(resources)
+ } catch (error) {
+ console.error(
+ 'failed to add resources to cache; make sure requests exists and that there are no duplicates',
+ error
+ )
+ }
+}
+
+/**
+ * Puts a response in the cache.
+ * @async
+ * @function putInCache
+ * @param {Request} request - The request to be cached.
+ * @param {Response} response - The response to be cached.
+ * @returns {Promise} A promise that resolves when the response has been added to the cache.
+ */
+const putInCache = async (request, response) => {
+ const cache = await caches.open(cacheName)
+
+ if (response.ok) {
+ console.info('adding one response to cache...', request.url)
+ cache.put(request, response)
+ }
+}
+
+const networkFirst = async ({ request, fallbackUrl }) => {
+ const cache = await caches.open(cacheName)
+
+ try {
+ // Try to get the resource from the network for 5 seconds
+ const responseFromNetwork = await fetch(request.clone())
+ putInCache(request, responseFromNetwork.clone())
+ console.info('using network response', responseFromNetwork.url)
+ return responseFromNetwork
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ } catch (error) {
+ // Try get the resource from the cache
+ const responseFromCache = await cache.match(request)
+ if (responseFromCache) {
+ console.info('using cached response...', responseFromCache.url)
+ return responseFromCache
+ }
+
+ // If fallback is provided, try to use it, otherwise return error
+ if (fallbackUrl) {
+ const fallbackResponse = await cache.match(fallbackUrl)
+ if (fallbackResponse) {
+ console.info('using fallback cached response...', fallbackResponse.url)
+ return fallbackResponse
+ }
+ }
+
+ // when even the fallback response is not available,
+ // there is nothing we can do, but we must always
+ // return a Response object
+ return new Response('Network error happened', {
+ status: 408,
+ headers: { 'Content-Type': 'text/plain' },
+ })
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+self.addEventListener('activate', (event) => {
+ console.info('activating service worker...')
+ cleanOldCaches()
+})
+
+self.addEventListener('install', (event) => {
+ console.info('installing service worker...')
+ self.skipWaiting() // go straight to activate
+
+ event.waitUntil(addResourcesToCache(__assets ?? []))
+})
+
+self.addEventListener('fetch', (event) => {
+ console.info('fetch happened', { data: event })
+
+ event.respondWith(
+ networkFirst({
+ request: event.request,
+ fallbackUrl: './',
+ })
+ )
+})
\ No newline at end of file
diff --git a/demo-static/tsconfig.json b/demo-static/tsconfig.json
new file mode 100644
index 0000000..8bf91d3
--- /dev/null
+++ b/demo-static/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "astro/tsconfigs/strict",
+ "include": [".astro/types.d.ts", "**/*"],
+ "exclude": ["dist"]
+}