@growth-labs/push 0.1.3

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.
Files changed (87) hide show
  1. package/README.md +106 -0
  2. package/dist/client/push-optin.d.ts +24 -0
  3. package/dist/client/push-optin.d.ts.map +1 -0
  4. package/dist/client/push-optin.js +122 -0
  5. package/dist/client/push-optin.js.map +1 -0
  6. package/dist/client/push-sw.d.ts +3 -0
  7. package/dist/client/push-sw.d.ts.map +1 -0
  8. package/dist/client/push-sw.js +36 -0
  9. package/dist/client/push-sw.js.map +1 -0
  10. package/dist/db/schema.d.ts +178 -0
  11. package/dist/db/schema.d.ts.map +1 -0
  12. package/dist/db/schema.js +14 -0
  13. package/dist/db/schema.js.map +1 -0
  14. package/dist/index.d.ts +4 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +56 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/middleware/push.d.ts +2 -0
  19. package/dist/middleware/push.d.ts.map +1 -0
  20. package/dist/middleware/push.js +10 -0
  21. package/dist/middleware/push.js.map +1 -0
  22. package/dist/options.d.ts +108 -0
  23. package/dist/options.d.ts.map +1 -0
  24. package/dist/options.js +36 -0
  25. package/dist/options.js.map +1 -0
  26. package/dist/routes/subscribe.d.ts +3 -0
  27. package/dist/routes/subscribe.d.ts.map +1 -0
  28. package/dist/routes/subscribe.js +68 -0
  29. package/dist/routes/subscribe.js.map +1 -0
  30. package/dist/routes/unsubscribe.d.ts +3 -0
  31. package/dist/routes/unsubscribe.d.ts.map +1 -0
  32. package/dist/routes/unsubscribe.js +24 -0
  33. package/dist/routes/unsubscribe.js.map +1 -0
  34. package/dist/types.d.ts +90 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +2 -0
  37. package/dist/types.js.map +1 -0
  38. package/dist/utils/analytics.d.ts +47 -0
  39. package/dist/utils/analytics.d.ts.map +1 -0
  40. package/dist/utils/analytics.js +78 -0
  41. package/dist/utils/analytics.js.map +1 -0
  42. package/dist/utils/cleanup.d.ts +12 -0
  43. package/dist/utils/cleanup.d.ts.map +1 -0
  44. package/dist/utils/cleanup.js +18 -0
  45. package/dist/utils/cleanup.js.map +1 -0
  46. package/dist/utils/composer.d.ts +95 -0
  47. package/dist/utils/composer.d.ts.map +1 -0
  48. package/dist/utils/composer.js +98 -0
  49. package/dist/utils/composer.js.map +1 -0
  50. package/dist/utils/index.d.ts +10 -0
  51. package/dist/utils/index.d.ts.map +1 -0
  52. package/dist/utils/index.js +10 -0
  53. package/dist/utils/index.js.map +1 -0
  54. package/dist/utils/queue.d.ts +40 -0
  55. package/dist/utils/queue.d.ts.map +1 -0
  56. package/dist/utils/queue.js +69 -0
  57. package/dist/utils/queue.js.map +1 -0
  58. package/dist/utils/scheduled.d.ts +105 -0
  59. package/dist/utils/scheduled.d.ts.map +1 -0
  60. package/dist/utils/scheduled.js +75 -0
  61. package/dist/utils/scheduled.js.map +1 -0
  62. package/dist/utils/send.d.ts +23 -0
  63. package/dist/utils/send.d.ts.map +1 -0
  64. package/dist/utils/send.js +99 -0
  65. package/dist/utils/send.js.map +1 -0
  66. package/dist/utils/subscriptions.d.ts +21 -0
  67. package/dist/utils/subscriptions.d.ts.map +1 -0
  68. package/dist/utils/subscriptions.js +84 -0
  69. package/dist/utils/subscriptions.js.map +1 -0
  70. package/dist/utils/turnstile.d.ts +5 -0
  71. package/dist/utils/turnstile.d.ts.map +1 -0
  72. package/dist/utils/turnstile.js +22 -0
  73. package/dist/utils/turnstile.js.map +1 -0
  74. package/dist/utils/vapid.d.ts +9 -0
  75. package/dist/utils/vapid.d.ts.map +1 -0
  76. package/dist/utils/vapid.js +23 -0
  77. package/dist/utils/vapid.js.map +1 -0
  78. package/package.json +77 -0
  79. package/src/client/push-optin.ts +189 -0
  80. package/src/client/push-sw.d.ts +3 -0
  81. package/src/client/push-sw.d.ts.map +1 -0
  82. package/src/client/push-sw.js +25 -0
  83. package/src/client/push-sw.js.map +1 -0
  84. package/src/client/push-sw.ts +45 -0
  85. package/src/components/PushOptIn.astro +53 -0
  86. package/src/components/index.ts +1 -0
  87. package/src/virtual.d.ts +5 -0
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @growth-labs/push
2
+
3
+ Web Push API integration for browser notifications. VAPID auth, D1 subscription storage, Turnstile-protected endpoints, Queue-based batch delivery. Sends directly to FCM/Mozilla/Apple push endpoints — no third-party push service.
4
+
5
+ **No consent package dependency.** Browser's native permission prompt ("Allow"/"Block") constitutes GDPR consent for push.
6
+
7
+ **Web Crypto API only.** Uses `@block65/webcrypto-web-push` for VAPID signing (ECDSA P-256) and RFC 8291 encryption — no Node.js `crypto` dependency.
8
+
9
+ ## Config
10
+
11
+ ```typescript
12
+ import push from '@growth-labs/push'
13
+
14
+ push({
15
+ vapidPublicKey: 'BDd8...', // URL-safe base64
16
+ vapidPrivateKey: '...', // JWK JSON string (via Cloudflare Secrets)
17
+ vapidSubject: 'mailto:admin@fedweek.com',
18
+ d1Binding: 'SITE_DB',
19
+ queueBinding: 'PUSH_QUEUE',
20
+ turnstileSiteKey: '...',
21
+ turnstileSecretKey: '...',
22
+ defaultIcon: '/icons/notification.png',
23
+ defaultTtl: 86400, // 24 hours
24
+ defaultUrgency: 'normal',
25
+ batchSize: 100, // Subscriptions per Queue message
26
+ cleanupAfterDays: 90, // Remove stale subscriptions
27
+ })
28
+ ```
29
+
30
+ ## What It Injects
31
+
32
+ **Middleware:** Injects VAPID public key into `context.locals.pushVapidKey`.
33
+
34
+ **Routes:**
35
+ - `POST /api/push/subscribe` — Turnstile-protected subscription endpoint
36
+ - `POST /api/push/unsubscribe` — remove subscription
37
+
38
+ **Component:** `<PushOptIn />` — opt-in/opt-out button. Vanilla JS. Handles full lifecycle: check support → check permission → request → subscribe → POST to server.
39
+
40
+ ## Sending Notifications (Consumer Calls)
41
+
42
+ ```typescript
43
+ import { sendPushNotification, enqueuePushBatchAll } from '@growth-labs/push/utils'
44
+
45
+ // Single send
46
+ await sendPushNotification(subscription, { title: 'Breaking', body: '...' }, sendContext)
47
+
48
+ // Batch send to all subscribers (via Queue)
49
+ await enqueuePushBatchAll(env.SITE_DB, payload, { queue: env.PUSH_QUEUE, batchSize: 100 })
50
+ ```
51
+
52
+ ## Queue Consumer
53
+
54
+ Package provides handler, consumer wires it up:
55
+
56
+ ```typescript
57
+ import { handlePushQueue } from '@growth-labs/push/utils'
58
+
59
+ export default {
60
+ async queue(batch, env) {
61
+ await handlePushQueue(batch, {
62
+ db: env.SITE_DB,
63
+ vapid: { subject: '...', publicKey: '...', privateKey: env.VAPID_PRIVATE_KEY },
64
+ defaults: { icon: '/icons/notification.png', ttl: 86400, urgency: 'normal' },
65
+ })
66
+ }
67
+ }
68
+ ```
69
+
70
+ **VAPID credentials passed via `QueueConsumerContext` at runtime — never in Queue messages.**
71
+
72
+ ## D1 Tables (prefixed `gl_`)
73
+
74
+ - `gl_push_subscriptions` — endpoint, p256dh key, auth key, topics, failure_count, last_delivery_at
75
+
76
+ ## VAPID Key Setup (One-Time)
77
+
78
+ ```bash
79
+ npx @growth-labs/push generate-vapid
80
+ # Store private key:
81
+ npx wrangler secret put VAPID_PRIVATE_KEY
82
+ npx wrangler secret put VAPID_PUBLIC_KEY
83
+ ```
84
+
85
+ ## Wrangler Bindings
86
+
87
+ ```toml
88
+ [[d1_databases]]
89
+ binding = "SITE_DB"
90
+ database_id = "..."
91
+
92
+ [[queues.producers]]
93
+ binding = "PUSH_QUEUE"
94
+ queue = "push-sends"
95
+
96
+ [[queues.consumers]]
97
+ queue = "push-sends"
98
+ max_batch_size = 5
99
+ ```
100
+
101
+ ## Key Patterns
102
+
103
+ - Virtual module: `virtual:growth-labs/push/config`
104
+ - Expired subscriptions (404/410 from push service) auto-cleaned
105
+ - 10+ consecutive failures → subscription removed
106
+ - `.astro` component files ship as source, not compiled
@@ -0,0 +1,24 @@
1
+ interface PushOptInDependencies {
2
+ navigator: {
3
+ serviceWorker: {
4
+ register(url: string): Promise<ServiceWorkerRegistration>;
5
+ ready: Promise<ServiceWorkerRegistration>;
6
+ getRegistration(url?: string): Promise<ServiceWorkerRegistration | undefined>;
7
+ };
8
+ };
9
+ window: Window & {
10
+ turnstile?: {
11
+ render(container: HTMLElement, options: {
12
+ sitekey: string;
13
+ callback(token: string): void;
14
+ 'error-callback'(): void;
15
+ }): void;
16
+ };
17
+ };
18
+ document: Document & {
19
+ dispatchEvent(event: CustomEvent): boolean;
20
+ };
21
+ }
22
+ export declare function initPushOptIn(root: ParentNode, deps?: PushOptInDependencies): void;
23
+ export {};
24
+ //# sourceMappingURL=push-optin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-optin.d.ts","sourceRoot":"","sources":["../../src/client/push-optin.ts"],"names":[],"mappings":"AASA,UAAU,qBAAqB;IAC9B,SAAS,EAAE;QACV,aAAa,EAAE;YACd,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAA;YACzD,KAAK,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAA;YACzC,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAAA;SAC7E,CAAA;KACD,CAAA;IACD,MAAM,EAAE,MAAM,GAAG;QAChB,SAAS,CAAC,EAAE;YACX,MAAM,CACL,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE;gBACR,OAAO,EAAE,MAAM,CAAA;gBACf,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;gBAC7B,gBAAgB,IAAI,IAAI,CAAA;aACxB,GACC,IAAI,CAAA;SACP,CAAA;KACD,CAAA;IACD,QAAQ,EAAE,QAAQ,GAAG;QACpB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAA;KAC1C,CAAA;CACD;AAuCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,wBAAoB,GAAG,IAAI,CAqH9E"}
@@ -0,0 +1,122 @@
1
+ /// <reference lib="dom" />
2
+ /// <reference lib="dom.iterable" />
3
+ function getDependencies() {
4
+ return globalThis;
5
+ }
6
+ function urlSafeBase64ToUint8Array(base64) {
7
+ const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
8
+ const binary = atob(padded.replace(/-/g, '+').replace(/_/g, '/'));
9
+ return Uint8Array.from(binary, (c) => c.charCodeAt(0));
10
+ }
11
+ function getTurnstileToken(windowObject, siteKey, container) {
12
+ return new Promise((resolve, reject) => {
13
+ container.hidden = false;
14
+ if (typeof windowObject.turnstile === 'undefined') {
15
+ reject(new Error('Turnstile script not loaded'));
16
+ return;
17
+ }
18
+ windowObject.turnstile.render(container, {
19
+ sitekey: siteKey,
20
+ callback: (token) => {
21
+ container.hidden = true;
22
+ resolve(token);
23
+ },
24
+ 'error-callback': () => {
25
+ container.hidden = true;
26
+ reject(new Error('Turnstile challenge failed'));
27
+ },
28
+ });
29
+ });
30
+ }
31
+ export function initPushOptIn(root, deps = getDependencies()) {
32
+ const containers = root.querySelectorAll('.gl-push-optin');
33
+ containers.forEach((container) => {
34
+ const btn = container.querySelector('[data-push-action="toggle"]');
35
+ const unsupported = container.querySelector('[data-push-state="unsupported"]');
36
+ const turnstileContainer = container.querySelector('[data-push-turnstile]');
37
+ if (!btn || !unsupported || !turnstileContainer) {
38
+ return;
39
+ }
40
+ const button = btn;
41
+ const vapidPublicKey = container.getAttribute('data-vapid-public-key') ?? '';
42
+ const subscribeUrl = container.getAttribute('data-subscribe-url') ?? '/api/push/subscribe';
43
+ const unsubscribeUrl = container.getAttribute('data-unsubscribe-url') ?? '/api/push/unsubscribe';
44
+ const swUrl = container.getAttribute('data-sw-url') ?? '/sw.js';
45
+ const turnstileSiteKey = container.getAttribute('data-turnstile-site-key') ?? '';
46
+ if (!('serviceWorker' in deps.navigator) || !('PushManager' in deps.window)) {
47
+ unsupported.hidden = false;
48
+ return;
49
+ }
50
+ button.hidden = false;
51
+ function showState(state) {
52
+ container.querySelectorAll('[data-push-state]').forEach((el) => {
53
+ ;
54
+ el.hidden = el.getAttribute('data-push-state') !== state;
55
+ });
56
+ button.hidden = state === 'unsupported';
57
+ button.disabled = state === 'subscribing' || state === 'denied';
58
+ }
59
+ async function checkState() {
60
+ const registration = await deps.navigator.serviceWorker.getRegistration(swUrl);
61
+ if (!registration) {
62
+ showState('prompt');
63
+ return;
64
+ }
65
+ const subscription = await registration.pushManager.getSubscription();
66
+ showState(subscription ? 'subscribed' : 'prompt');
67
+ }
68
+ button.addEventListener('click', async () => {
69
+ try {
70
+ // Register before awaiting `ready` so the first click cannot stall forever.
71
+ await deps.navigator.serviceWorker.register(swUrl);
72
+ const registration = await deps.navigator.serviceWorker.ready;
73
+ const existing = await registration.pushManager.getSubscription();
74
+ if (existing) {
75
+ await existing.unsubscribe();
76
+ await fetch(unsubscribeUrl, {
77
+ method: 'POST',
78
+ headers: { 'Content-Type': 'application/json' },
79
+ body: JSON.stringify({ endpoint: existing.endpoint }),
80
+ });
81
+ deps.document.dispatchEvent(new CustomEvent('gl:push_unsubscribed', {
82
+ detail: { endpoint: existing.endpoint },
83
+ }));
84
+ showState('prompt');
85
+ return;
86
+ }
87
+ showState('subscribing');
88
+ const turnstileToken = await getTurnstileToken(deps.window, turnstileSiteKey, turnstileContainer);
89
+ const subscription = await registration.pushManager.subscribe({
90
+ userVisibleOnly: true,
91
+ applicationServerKey: urlSafeBase64ToUint8Array(vapidPublicKey),
92
+ });
93
+ const response = await fetch(subscribeUrl, {
94
+ method: 'POST',
95
+ headers: { 'Content-Type': 'application/json' },
96
+ body: JSON.stringify({
97
+ subscription: subscription.toJSON(),
98
+ turnstileToken,
99
+ }),
100
+ });
101
+ if (!response.ok) {
102
+ throw new Error('Server rejected subscription');
103
+ }
104
+ deps.document.dispatchEvent(new CustomEvent('gl:push_subscribed', {
105
+ detail: { endpoint: subscription.endpoint },
106
+ }));
107
+ showState('subscribed');
108
+ }
109
+ catch (err) {
110
+ if (Notification.permission === 'denied') {
111
+ showState('denied');
112
+ }
113
+ else {
114
+ showState('error');
115
+ console.error('[gl-push]', err);
116
+ }
117
+ }
118
+ });
119
+ checkState();
120
+ });
121
+ }
122
+ //# sourceMappingURL=push-optin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-optin.js","sourceRoot":"","sources":["../../src/client/push-optin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function handlePush(event: PushEvent): void;
2
+ export declare function handleNotificationClick(event: NotificationEvent): void;
3
+ //# sourceMappingURL=push-sw.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-sw.d.ts","sourceRoot":"","sources":["../../src/client/push-sw.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAiBjD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAsBtE"}
@@ -0,0 +1,36 @@
1
+ /// <reference lib="webworker" />
2
+ export function handlePush(event) {
3
+ const data = event.data?.json() ?? {};
4
+ const options = {
5
+ body: data.body ?? '',
6
+ icon: data.icon,
7
+ image: data.image,
8
+ tag: data.tag,
9
+ data: {
10
+ url: data.url,
11
+ actionUrl: data.action?.url,
12
+ tag: data.tag,
13
+ },
14
+ actions: data.action ? [{ action: 'primary', title: data.action.title }] : [],
15
+ };
16
+ event.waitUntil(self.registration.showNotification(data.title ?? 'Notification', options));
17
+ }
18
+ export function handleNotificationClick(event) {
19
+ event.notification.close();
20
+ const data = event.notification.data ?? {};
21
+ const url = event.action === 'primary' && data.actionUrl ? data.actionUrl : data.url;
22
+ if (url) {
23
+ // Notify all visible clients so they can emit gl:push_notification_clicked
24
+ event.waitUntil(self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((windowClients) => {
25
+ for (const client of windowClients) {
26
+ client.postMessage({
27
+ type: 'gl:push_notification_clicked',
28
+ tag: data.tag,
29
+ url,
30
+ });
31
+ }
32
+ return self.clients.openWindow(url);
33
+ }));
34
+ }
35
+ }
36
+ //# sourceMappingURL=push-sw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-sw.js","sourceRoot":"","sources":["../../src/client/push-sw.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAGjC,MAAM,UAAU,UAAU,CAAC,KAAgB;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IAErC,MAAM,OAAO,GAAG;QACf,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,IAAI,EAAE;YACL,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG;YAC3B,GAAG,EAAE,IAAI,CAAC,GAAG;SACb;QACD,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KACrB,CAAA;IAEzD,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,IAAI,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;AAC3F,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAwB;IAC/D,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,CAAA;IAE1B,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAA;IAE1C,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAA;IAEpF,IAAI,GAAG,EAAE,CAAC;QACT,2EAA2E;QAC3E,KAAK,CAAC,SAAS,CACd,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE;YAC3F,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACpC,MAAM,CAAC,WAAW,CAAC;oBAClB,IAAI,EAAE,8BAA8B;oBACpC,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,GAAG;iBACH,CAAC,CAAA;YACH,CAAC;YACD,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACpC,CAAC,CAAC,CACF,CAAA;IACF,CAAC;AACF,CAAC"}
@@ -0,0 +1,178 @@
1
+ export declare const pushSubscriptions: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
2
+ name: "gl_push_subscriptions";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
6
+ name: "id";
7
+ tableName: "gl_push_subscriptions";
8
+ dataType: "string";
9
+ columnType: "SQLiteText";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: false;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: [string, ...string[]];
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, object>;
22
+ endpoint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
23
+ name: "endpoint";
24
+ tableName: "gl_push_subscriptions";
25
+ dataType: "string";
26
+ columnType: "SQLiteText";
27
+ data: string;
28
+ driverParam: string;
29
+ notNull: true;
30
+ hasDefault: false;
31
+ isPrimaryKey: false;
32
+ isAutoincrement: false;
33
+ hasRuntimeDefault: false;
34
+ enumValues: [string, ...string[]];
35
+ baseColumn: never;
36
+ identity: undefined;
37
+ generated: undefined;
38
+ }, object>;
39
+ keyP256dh: import("drizzle-orm/sqlite-core").SQLiteColumn<{
40
+ name: "key_p256dh";
41
+ tableName: "gl_push_subscriptions";
42
+ dataType: "string";
43
+ columnType: "SQLiteText";
44
+ data: string;
45
+ driverParam: string;
46
+ notNull: true;
47
+ hasDefault: false;
48
+ isPrimaryKey: false;
49
+ isAutoincrement: false;
50
+ hasRuntimeDefault: false;
51
+ enumValues: [string, ...string[]];
52
+ baseColumn: never;
53
+ identity: undefined;
54
+ generated: undefined;
55
+ }, object>;
56
+ keyAuth: import("drizzle-orm/sqlite-core").SQLiteColumn<{
57
+ name: "key_auth";
58
+ tableName: "gl_push_subscriptions";
59
+ dataType: "string";
60
+ columnType: "SQLiteText";
61
+ data: string;
62
+ driverParam: string;
63
+ notNull: true;
64
+ hasDefault: false;
65
+ isPrimaryKey: false;
66
+ isAutoincrement: false;
67
+ hasRuntimeDefault: false;
68
+ enumValues: [string, ...string[]];
69
+ baseColumn: never;
70
+ identity: undefined;
71
+ generated: undefined;
72
+ }, object>;
73
+ topics: import("drizzle-orm/sqlite-core").SQLiteColumn<{
74
+ name: "topics";
75
+ tableName: "gl_push_subscriptions";
76
+ dataType: "string";
77
+ columnType: "SQLiteText";
78
+ data: string;
79
+ driverParam: string;
80
+ notNull: false;
81
+ hasDefault: false;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: [string, ...string[]];
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, object>;
90
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
91
+ name: "created_at";
92
+ tableName: "gl_push_subscriptions";
93
+ dataType: "date";
94
+ columnType: "SQLiteTimestamp";
95
+ data: Date;
96
+ driverParam: number;
97
+ notNull: true;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: undefined;
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, object>;
107
+ lastDeliveryAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
108
+ name: "last_delivery_at";
109
+ tableName: "gl_push_subscriptions";
110
+ dataType: "date";
111
+ columnType: "SQLiteTimestamp";
112
+ data: Date;
113
+ driverParam: number;
114
+ notNull: false;
115
+ hasDefault: false;
116
+ isPrimaryKey: false;
117
+ isAutoincrement: false;
118
+ hasRuntimeDefault: false;
119
+ enumValues: undefined;
120
+ baseColumn: never;
121
+ identity: undefined;
122
+ generated: undefined;
123
+ }, object>;
124
+ failureCount: import("drizzle-orm/sqlite-core").SQLiteColumn<{
125
+ name: "failure_count";
126
+ tableName: "gl_push_subscriptions";
127
+ dataType: "number";
128
+ columnType: "SQLiteInteger";
129
+ data: number;
130
+ driverParam: number;
131
+ notNull: true;
132
+ hasDefault: true;
133
+ isPrimaryKey: false;
134
+ isAutoincrement: false;
135
+ hasRuntimeDefault: false;
136
+ enumValues: undefined;
137
+ baseColumn: never;
138
+ identity: undefined;
139
+ generated: undefined;
140
+ }, object>;
141
+ userAgent: import("drizzle-orm/sqlite-core").SQLiteColumn<{
142
+ name: "user_agent";
143
+ tableName: "gl_push_subscriptions";
144
+ dataType: "string";
145
+ columnType: "SQLiteText";
146
+ data: string;
147
+ driverParam: string;
148
+ notNull: false;
149
+ hasDefault: false;
150
+ isPrimaryKey: false;
151
+ isAutoincrement: false;
152
+ hasRuntimeDefault: false;
153
+ enumValues: [string, ...string[]];
154
+ baseColumn: never;
155
+ identity: undefined;
156
+ generated: undefined;
157
+ }, object>;
158
+ country: import("drizzle-orm/sqlite-core").SQLiteColumn<{
159
+ name: "country";
160
+ tableName: "gl_push_subscriptions";
161
+ dataType: "string";
162
+ columnType: "SQLiteText";
163
+ data: string;
164
+ driverParam: string;
165
+ notNull: false;
166
+ hasDefault: false;
167
+ isPrimaryKey: false;
168
+ isAutoincrement: false;
169
+ hasRuntimeDefault: false;
170
+ enumValues: [string, ...string[]];
171
+ baseColumn: never;
172
+ identity: undefined;
173
+ generated: undefined;
174
+ }, object>;
175
+ };
176
+ dialect: "sqlite";
177
+ }>;
178
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW5B,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
2
+ export const pushSubscriptions = sqliteTable('gl_push_subscriptions', {
3
+ id: text('id').primaryKey(),
4
+ endpoint: text('endpoint').notNull().unique(),
5
+ keyP256dh: text('key_p256dh').notNull(),
6
+ keyAuth: text('key_auth').notNull(),
7
+ topics: text('topics'),
8
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
9
+ lastDeliveryAt: integer('last_delivery_at', { mode: 'timestamp' }),
10
+ failureCount: integer('failure_count').notNull().default(0),
11
+ userAgent: text('user_agent'),
12
+ country: text('country'),
13
+ });
14
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAEpE,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC,uBAAuB,EAAE;IACrE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE;IAC7C,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IACvC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;IACnC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE;IACjE,cAAc,EAAE,OAAO,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAClE,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC;IAC7B,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;CACxB,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ import { type PushOptions } from './options.js';
3
+ export default function push(options: PushOptions): AstroIntegration;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,cAAc,CAAA;AAElE,MAAM,CAAC,OAAO,UAAU,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,gBAAgB,CA0DnE"}
package/dist/index.js ADDED
@@ -0,0 +1,56 @@
1
+ import { pushOptionsSchema } from './options.js';
2
+ export default function push(options) {
3
+ const resolved = pushOptionsSchema.parse(options);
4
+ const virtualConfig = {
5
+ vapidPublicKey: resolved.vapidPublicKey,
6
+ d1Binding: resolved.d1Binding,
7
+ queueBinding: resolved.queueBinding,
8
+ defaults: resolved.defaults,
9
+ queue: resolved.queue,
10
+ turnstile: resolved.turnstile,
11
+ routes: resolved.routes,
12
+ cleanup: resolved.cleanup,
13
+ };
14
+ const virtualModuleId = 'virtual:growth-labs/push/config';
15
+ const resolvedVirtualModuleId = `\0${virtualModuleId}`;
16
+ return {
17
+ name: '@growth-labs/push',
18
+ hooks: {
19
+ 'astro:config:setup': ({ addMiddleware, injectRoute, updateConfig }) => {
20
+ updateConfig({
21
+ vite: {
22
+ plugins: [
23
+ {
24
+ name: 'growth-labs-push-config',
25
+ resolveId(id) {
26
+ if (id === virtualModuleId)
27
+ return resolvedVirtualModuleId;
28
+ },
29
+ load(id) {
30
+ if (id === resolvedVirtualModuleId) {
31
+ return `export default ${JSON.stringify(virtualConfig)}`;
32
+ }
33
+ },
34
+ },
35
+ ],
36
+ },
37
+ });
38
+ addMiddleware({
39
+ entrypoint: '@growth-labs/push/middleware',
40
+ order: 'pre',
41
+ });
42
+ injectRoute({
43
+ pattern: resolved.routes.subscribe,
44
+ entrypoint: '@growth-labs/push/routes/subscribe',
45
+ prerender: false,
46
+ });
47
+ injectRoute({
48
+ pattern: resolved.routes.unsubscribe,
49
+ entrypoint: '@growth-labs/push/routes/unsubscribe',
50
+ prerender: false,
51
+ });
52
+ },
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAElE,MAAM,CAAC,OAAO,UAAU,IAAI,CAAC,OAAoB;IAChD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAEjD,MAAM,aAAa,GAAG;QACrB,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;KACzB,CAAA;IAED,MAAM,eAAe,GAAG,iCAAiC,CAAA;IACzD,MAAM,uBAAuB,GAAG,KAAK,eAAe,EAAE,CAAA;IAEtD,OAAO;QACN,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE;YACN,oBAAoB,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,EAAE;gBACtE,YAAY,CAAC;oBACZ,IAAI,EAAE;wBACL,OAAO,EAAE;4BACR;gCACC,IAAI,EAAE,yBAAyB;gCAC/B,SAAS,CAAC,EAAE;oCACX,IAAI,EAAE,KAAK,eAAe;wCAAE,OAAO,uBAAuB,CAAA;gCAC3D,CAAC;gCACD,IAAI,CAAC,EAAE;oCACN,IAAI,EAAE,KAAK,uBAAuB,EAAE,CAAC;wCACpC,OAAO,kBAAkB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAA;oCACzD,CAAC;gCACF,CAAC;6BACD;yBACD;qBACD;iBACD,CAAC,CAAA;gBAEF,aAAa,CAAC;oBACb,UAAU,EAAE,8BAA8B;oBAC1C,KAAK,EAAE,KAAK;iBACZ,CAAC,CAAA;gBAEF,WAAW,CAAC;oBACX,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;oBAClC,UAAU,EAAE,oCAAoC;oBAChD,SAAS,EAAE,KAAK;iBAChB,CAAC,CAAA;gBAEF,WAAW,CAAC;oBACX,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW;oBACpC,UAAU,EAAE,sCAAsC;oBAClD,SAAS,EAAE,KAAK;iBAChB,CAAC,CAAA;YACH,CAAC;SACD;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const onRequest: import("astro").MiddlewareHandler;
2
+ //# sourceMappingURL=push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/middleware/push.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,mCAMpB,CAAA"}
@@ -0,0 +1,10 @@
1
+ import config from 'virtual:growth-labs/push/config';
2
+ import { defineMiddleware } from 'astro/middleware';
3
+ export const onRequest = defineMiddleware(async (context, next) => {
4
+ ;
5
+ context.locals.push = {
6
+ vapidPublicKey: config.vapidPublicKey,
7
+ };
8
+ return next();
9
+ });
10
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/middleware/push.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,iCAAiC,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEnD,MAAM,CAAC,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IACjE,CAAC;IAAC,OAAO,CAAC,MAAkC,CAAC,IAAI,GAAG;QACnD,cAAc,EAAE,MAAM,CAAC,cAAc;KACrC,CAAA;IAED,OAAO,IAAI,EAAE,CAAA;AACd,CAAC,CAAC,CAAA"}