{"_id":"@dloizides/event-landing-kit","name":"@dloizides/event-landing-kit","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@dloizides/event-landing-kit","version":"1.0.0","description":"Framework-free toolkit for single-page event landing sites (dance socials, congresses): a configurable PWA service worker, live registration stats from a public ledger.json, a registration-deadline countdown with door-fallback swap, and a WhatsApp deep-li","keywords":["event","landing-page","service-worker","pwa","countdown","whatsapp","static-site"],"author":{"name":"dloizides"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/openmindednewby/event-landing-kit.git"},"homepage":"https://github.com/openmindednewby/event-landing-kit#readme","bugs":{"url":"https://github.com/openmindednewby/event-landing-kit/issues"},"main":"./dist/event-landing-kit.js","module":"./dist/event-landing-kit.mjs","types":"./dist/event-landing-kit.d.ts","exports":{".":{"browser":{"types":"./dist/event-landing-kit.d.ts","default":"./dist/event-landing-kit.js"},"require":{"types":"./dist/event-landing-kit.d.ts","default":"./dist/event-landing-kit.js"},"import":{"types":"./dist/event-landing-kit.d.mts","default":"./dist/event-landing-kit.mjs"},"default":{"types":"./dist/event-landing-kit.d.ts","default":"./dist/event-landing-kit.js"}},"./global":"./dist/event-landing-kit.global.js","./sw-core":"./dist/event-sw-core.global.js"},"sideEffects":false,"engines":{"node":">=18.0.0"},"scripts":{"build":"rimraf dist && tsup","build:watch":"tsup --watch","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","lint":"eslint src --ext .ts","lint:fix":"eslint src --ext .ts --fix","typecheck":"tsc --noEmit","clean":"rimraf dist","security:audit":"npm audit --audit-level=high","prepublishOnly":"npm run clean && npm run build && npm run test"},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.19.32","@typescript-eslint/eslint-plugin":"^7.0.0","@typescript-eslint/parser":"^7.0.0","eslint":"^8.57.0","jest":"^29.7.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","tsup":"^8.0.0","typescript":"^5.4.0"},"_id":"@dloizides/event-landing-kit@1.0.0","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-88CmJBgSh5UWiaUoITOYPrBIchuuLYVq7oNNoy2YHWyMks6waI522goMve0xOjIunYq4yabC9OthklKC+PCg3Q==","shasum":"2f6e648aca876f7c87445aa789cfa75632f96478","tarball":"https://registry.npmjs.org/@dloizides/event-landing-kit/-/event-landing-kit-1.0.0.tgz","fileCount":13,"unpackedSize":104587,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGNm0jm6k6UnIcybHX4kcEwIQyYf/iKRHCH4p+rhPj4DAiBKxX/1oZWRDqQDVv603TEhiZ21v4N/JAtkXeifBSZeww=="}]},"_npmUser":{"name":"dloizides","email":"loizidesdemetris@gmail.com"},"directories":{},"maintainers":[{"name":"dloizides","email":"loizidesdemetris@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/event-landing-kit_1.0.0_1781812716030_0.551269332457065"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-18T19:58:35.917Z","1.0.0":"2026-06-18T19:58:36.203Z","modified":"2026-06-18T19:58:36.384Z"},"maintainers":[{"name":"dloizides","email":"loizidesdemetris@gmail.com"}],"description":"Framework-free toolkit for single-page event landing sites (dance socials, congresses): a configurable PWA service worker, live registration stats from a public ledger.json, a registration-deadline countdown with door-fallback swap, and a WhatsApp deep-li","homepage":"https://github.com/openmindednewby/event-landing-kit#readme","keywords":["event","landing-page","service-worker","pwa","countdown","whatsapp","static-site"],"repository":{"type":"git","url":"git+https://github.com/openmindednewby/event-landing-kit.git"},"author":{"name":"dloizides"},"bugs":{"url":"https://github.com/openmindednewby/event-landing-kit/issues"},"license":"MIT","readme":"# @dloizides/event-landing-kit\n\nFramework-free toolkit for single-page **event landing sites** (dance socials,\ncongresses, one-off parties). Extracted from the hand-written\n[Kizomba Union CY](https://kizombaunioncy.dloizides.com) and\n[United by Salsa](https://unitedbysalsa.dloizides.com) sites, which duplicated\nthe same four pieces of logic with a copy-paste bug between them.\n\nIt ships **browser IIFE bundles** meant to be **vendored** into static sites that\nhave no build step (`<script src>` + `importScripts`), plus CJS/ESM for anyone who\ndoes build. Zero runtime dependencies.\n\n## What's in it\n\n| Piece | API | Replaces |\n|---|---|---|\n| **Service-worker core** | `self.EventSW.register({...})` | the per-site `sw.js` (network-first HTML, SWR assets, gated live paths) |\n| **Live registration stats** | `EventLandingKit.initLedgerStats({...})` | the `ledger.json` → counts widget |\n| **Deadline countdown** | `EventLandingKit.initCountdown({...})` | the register ↔ \"pay at the door\" swap + countdown |\n| **WhatsApp deep link** | `EventLandingKit.buildWhatsAppUrl(phone, lines)` | the `wa.me` URL builder in the register form |\n\n> The registration **form** itself stays per-site (each event has its own passes /\n> add-ons / pricing); only the WhatsApp-link builder is shared.\n\n## Vendoring into a build-step-less static site\n\nCopy the two IIFE files from `dist/` into the site (e.g. `assets/js/`):\n\n```\ndist/event-landing-kit.global.js  → assets/js/event-landing-kit.js\ndist/event-sw-core.global.js      → assets/js/event-sw-core.js\n```\n\n### Page kit\n\n```html\n<script src=\"/assets/js/event-landing-kit.js\"></script>\n<script>\n  EventLandingKit.initLedgerStats();             // defaults: /ledger/ledger.json, threshold 100\n  EventLandingKit.initCountdown({\n    deadlineMs: new Date('2026-05-16T13:00:00+03:00').getTime(),\n    strings: {\n      bookSubOpen:   'Reserve your pass, then pay via Revolut.',\n      bookSubClosed: 'Online payments closed — pay cash at the door.',\n    },\n  });\n  // In the register form's submit handler:\n  const url = EventLandingKit.buildWhatsAppUrl('35796650527', lines);\n</script>\n```\n\nBoth `initLedgerStats` and `initCountdown` default to the canonical element IDs\n(`reg-stats`, `reg-stat-total`, `register-countdown`, `cd-days`, `book-sub`, …)\nand no-op safely when an element is missing — so partial pages just work.\n\n### Service worker (`sw.js`)\n\n```js\nimportScripts('/assets/js/event-sw-core.js');\nself.EventSW.register({\n  cacheName: 'kucy-v185',     // bump on each asset change\n  cachePrefix: 'kucy-',       // cleanup deletes ONLY this site's caches\n  precache: ['/', '/index.html', '/manifest.webmanifest', '/assets/logo/icon-192.png'],\n  gatedPaths: ['/ledger/', '/door/', '/ticket/', '/media/', '/mediaTicket/', '/dj/'],\n  // fallbackDocument defaults to '/index.html'\n});\n```\n\n**`cachePrefix` fixes the original fork bug:** each site must clean up only its own\ncaches. (The pre-extraction UBS worker still purged `kucy-` caches — a leftover from\nbeing copied off the KUCY worker.)\n\n## Behaviour notes\n\n- **Strategy** is identical to the workers it replaces: HTML/navigation →\n  network-first (cache fallback → fallback document); other same-origin GETs →\n  stale-while-revalidate; cross-origin + gated live paths → pass-through.\n- The install step **per-item-catches** precache failures so one renamed/missing\n  asset doesn't fail the whole install. (The extracted core does this silently —\n  the original logged a `console.warn`.)\n- `initLedgerStats` exposes only aggregate counts (total / male / female / other /\n  not-specified, paid vs expected) and reveals the card only past the threshold.\n  It never throws — on any error the stats just stay hidden.\n- `initCountdown` is pure client-side: every visit re-checks the clock, so no\n  redeploy is needed at the cutover. It returns a controller with `stop()`.\n\n## Development\n\n```\nnpm install\nnpm run lint && npm run typecheck && npm test   # 100% coverage gate\nnpm run build                                    # dist/ (cjs + esm + iife + d.ts)\n```\n\nMIT © dloizides\n","readmeFilename":"README.md","_rev":"1-0012ebdad8232364fac9e5e6a1dda8d2"}