@lunora/notify 1.0.0-alpha.10 → 1.0.0-alpha.12
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/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/buildEngine-BZKpZXQ6.mjs +1 -0
- package/dist/packem_shared/{createNotify-jNlehALj.mjs → createNotify-DmK_8uPL.mjs} +1 -1
- package/dist/web.mjs +1 -1
- package/package.json +2 -2
- package/dist/packem_shared/buildEngine-Jlzf2Jzn.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -508,7 +508,7 @@ interface PushBroadcastJob {
|
|
|
508
508
|
/** Discriminator so a shared queue can multiplex message kinds. */
|
|
509
509
|
type: "lunora.push.broadcast";
|
|
510
510
|
}
|
|
511
|
-
/** The structural slice of a `@lunora/queue` producer (`ctx.queues
|
|
511
|
+
/** The structural slice of a `@lunora/queue` producer (`ctx.queues.<name>`) used here. */
|
|
512
512
|
interface QueueProducerLike {
|
|
513
513
|
send: (body: PushBroadcastJob) => Promise<void>;
|
|
514
514
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -508,7 +508,7 @@ interface PushBroadcastJob {
|
|
|
508
508
|
/** Discriminator so a shared queue can multiplex message kinds. */
|
|
509
509
|
type: "lunora.push.broadcast";
|
|
510
510
|
}
|
|
511
|
-
/** The structural slice of a `@lunora/queue` producer (`ctx.queues
|
|
511
|
+
/** The structural slice of a `@lunora/queue` producer (`ctx.queues.<name>`) used here. */
|
|
512
512
|
interface QueueProducerLike {
|
|
513
513
|
send: (body: PushBroadcastJob) => Promise<void>;
|
|
514
514
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{FCM_ENV_KEYS as e,WEB_PUSH_ENV_KEYS as t,fcmFromEnv as i,webPushFromEnv as f}from"./packem_shared/FCM_ENV_KEYS-D0tvRTLQ.mjs";import{defineNotify as n,isNotifyDefinition as u}from"./packem_shared/defineNotify-DLEy53HJ.mjs";import{createNotify as p}from"./packem_shared/createNotify-
|
|
1
|
+
import{FCM_ENV_KEYS as e,WEB_PUSH_ENV_KEYS as t,fcmFromEnv as i,webPushFromEnv as f}from"./packem_shared/FCM_ENV_KEYS-D0tvRTLQ.mjs";import{defineNotify as n,isNotifyDefinition as u}from"./packem_shared/defineNotify-DLEy53HJ.mjs";import{createNotify as p}from"./packem_shared/createNotify-DmK_8uPL.mjs";import{buildEngine as d,routingPushProvider as x}from"./packem_shared/buildEngine-BZKpZXQ6.mjs";import{enqueuePushBroadcast as c,runPushBroadcastJob as P}from"./packem_shared/enqueuePushBroadcast-tf1LqgzA.mjs";import{d1SubscriptionStore as b}from"./packem_shared/d1SubscriptionStore-67jpK0Vx.mjs";import{memorySubscriptionStore as N}from"./packem_shared/memorySubscriptionStore-FKZR4-fB.mjs";import{fcmId as g,isGoneError as y,normalizeRegisterInput as v,targetOf as B,webPushId as F}from"./packem_shared/fcmId-CFZ8IquF.mjs";export{e as FCM_ENV_KEYS,t as WEB_PUSH_ENV_KEYS,d as buildEngine,p as createNotify,b as d1SubscriptionStore,n as defineNotify,c as enqueuePushBroadcast,i as fcmFromEnv,g as fcmId,y as isGoneError,u as isNotifyDefinition,N as memorySubscriptionStore,v as normalizeRegisterInput,x as routingPushProvider,P as runPushBroadcastJob,B as targetOf,f as webPushFromEnv,F as webPushId};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createNotification as s}from"@visulima/notification";import{retryMiddleware as a,circuitBreakerMiddleware as n}from"@visulima/notification/middleware";import{fcmProvider as c}from"@visulima/notification/providers/fcm";import{webPushProvider as u}from"@visulima/notification/providers/web-push";const d=i=>{if(typeof i!="string")return typeof i=="object"&&i!==null&&"endpoint"in i;if(!i.startsWith("{"))return!1;try{const r=JSON.parse(i);return typeof r.endpoint=="string"&&typeof r.keys=="object"}catch{return!1}},f=i=>{const r=o=>{const e=d(o),t=e?i.webPush:i.fcm;if(t===void 0)throw new Error(e?"@lunora/notify: received a web-push target but no `webPush` channel is configured":"@lunora/notify: received an FCM token target but no `fcm` channel is configured");return t};return{channel:"push",id:"lunora-push-router",initialize:async()=>{await i.webPush?.initialize(),await i.fcm?.initialize()},isAvailable:()=>(i.webPush??i.fcm)!==void 0,send:o=>{const e=Array.isArray(o.to)?o.to[0]:o.to;return r(e).send(o)}}},w=i=>{const r=i.webPush===void 0?void 0:u(i.webPush),o=i.fcm===void 0?void 0:c(i.fcm),e={};(r!==void 0||o!==void 0)&&(e.push=f({fcm:o,webPush:r})),i.chat!==void 0&&(e.chat=i.chat),i.inApp!==void 0&&(e.inapp=i.inApp),i.webhook!==void 0&&(e.webhook=i.webhook);const t=s(e);return t.use(a()).use(n()),t};export{w as buildEngine,f as routingPushProvider};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraError as k}from"@lunora/errors";import{buildEngine as R}from"./buildEngine-
|
|
1
|
+
import{LunoraError as k}from"@lunora/errors";import{buildEngine as R}from"./buildEngine-BZKpZXQ6.mjs";import{memorySubscriptionStore as W}from"./memorySubscriptionStore-FKZR4-fB.mjs";import{normalizeRegisterInput as Q,targetOf as U,isGoneError as j}from"./fcmId-CFZ8IquF.mjs";const z=250,g=(o,l)=>typeof o=="function"?o(l):o,b=o=>o.successful?void 0:o.errorMessages.join("; "),G=(o,l)=>o.successful?"accepted":j(l)?"gone":"failed",L=async(o,l,c)=>{const d=Array.from({length:o.length});let h=0;const p=async()=>{for(;h<o.length;){const f=h;h+=1,d[f]=await c(o[f])}};return await Promise.all(Array.from({length:Math.min(l,o.length)},()=>p())),d},_=(o,l)=>({chat:g(o.chat,l),fcm:g(o.fcm,l),inApp:g(o.inApp,l),webhook:g(o.webhook,l),webPush:g(o.webPush,l)}),E=new WeakMap,q=(o,l)=>{let c=E.get(o);c===void 0&&(c=new WeakMap,E.set(o,c));let d=c.get(l);return d===void 0&&(d={warnedNoPushOriginAllowlist:!1,warnedNoStore:!1},c.set(l,d)),d},V=(o,l,c={})=>{const d=q(o,l);let h;c.engine===void 0?(d.engine??=R(_(o,l)),h=d.engine):h=c.engine,d.store??=o.store?.(l);let{store:p}=d;p===void 0&&(d.fallbackStore??=W(),!c.silent&&!d.warnedNoStore&&(d.warnedNoStore=!0,console.warn("@lunora/notify: no `store` configured — using a non-durable in-memory subscription store. Configure `store: (env) => d1SubscriptionStore(env.DB)` for production.")),p=d.fallbackStore);const f=p,M=Math.max(1,c.concurrency??10),S=Math.max(1,c.broadcastPageSize??z),{log:T,metrics:P}=c,w=(t,e,r,i=1)=>{P?.count("notify.send",i,{channel:t,provider:e??t,status:r})},v=(t,e,r)=>{T?.warn(`notify ${t} delivery failed`,{channel:t,provider:e??t,status:"failed",...r})},N=(t,e)=>{P?.count("notify.skipped",1,{channel:t,reason:e})},$=()=>{const t=o.allowedPushOrigins!==void 0&&o.allowedPushOrigins.length>0;c.silent||t||d.warnedNoPushOriginAllowlist||(d.warnedNoPushOriginAllowlist=!0,console.warn("@lunora/notify: Web Push registered without `allowedPushOrigins` — the endpoint host is validated by a string classifier that does NOT resolve DNS, so a public hostname resolving to a private/internal IP (e.g. `https://127.0.0.1.nip.io/…`) is NOT blocked. Set `allowedPushOrigins` to the exact push-service origins to close DNS rebinding."))},I=async t=>(await f.list(t)).map(({keys:e,token:r,...i})=>i),C=async t=>{if(typeof t!="string")return t;const e=await f.get(t);if(e===void 0)throw new k("BAD_REQUEST",`@lunora/notify: no registered subscription with id "${t}"`);return e},O=async(t,e,r)=>{let i,s,n;try{i=await h.sendToChannel("push",{...e,to:U(t)}),s=b(i),n=G(i,s)}catch(u){n="failed",s=u instanceof Error?u.message:String(u)}try{n==="accepted"?await f.markStatus(t.id,"ok"):n==="gone"?await f.delete(t.id):await f.markStatus(t.id,"failed",s)}catch{}return n==="failed"&&v("push",t.kind,{error:s,subscriptionId:t.id,userId:t.userId??null}),r&&w("push",t.kind,n),{error:s,receipt:i,status:n}},D=async(t,e)=>{const r=await L(e,M,async n=>{const{error:u,status:a}=await O(n,t,!1);return{error:u,kind:n.kind,status:a,subscription:n}}),i=new Map;for(const{kind:n,status:u}of r){const a=`${n} ${u}`,m=i.get(a);m===void 0?i.set(a,{count:1,kind:n,status:u}):m.count+=1}for(const{count:n,kind:u,status:a}of i.values())w("push",u,a,n);const s=r.map(({error:n,status:u,subscription:a})=>u==="accepted"?{id:a.id,status:"ok"}:u==="gone"?{error:n,id:a.id,status:"expired"}:{error:n,id:a.id,status:"failed"});return{failed:s.filter(n=>n.status==="failed").length,outcomes:s,pruned:s.filter(n=>n.status==="expired").length,sent:s.filter(n=>n.status==="ok").length,total:s.length}},A=async(t,e)=>{if(e?.limit!==void 0&&e.limit<=0)return{nextCursor:void 0,result:{failed:0,outcomes:[],pruned:0,sent:0,total:0}};const r=e?.limit!==void 0&&e.limit>0?Math.trunc(e.limit):void 0,i=r===void 0?S:Math.min(r,S),s=await f.list({after:e?.after,kind:e?.kind,limit:i+1,userId:e?.userId}),n=e?.after===void 0?s:s.filter(B=>B.id>e.after),u=n.length>i,a=u?n.slice(0,i):n;a.length===0&&e?.after===void 0&&N("push","no-subscriptions-matched");const m=await D(t,a);return{nextCursor:u?a[a.length-1]?.id:void 0,result:m}},x={broadcast:async(t,e)=>{const r={failed:0,outcomes:[],pruned:0,sent:0,total:0};let i=e?.after;const s=e?.limit;if(s!==void 0&&s<=0)return r;for(;;){const n=s===void 0?{...e,after:i}:{...e,after:i,limit:s-r.total},{nextCursor:u,result:a}=await A(t,n);if(r.failed+=a.failed,r.pruned+=a.pruned,r.sent+=a.sent,r.total+=a.total,r.outcomes.push(...a.outcomes),s!==void 0&&r.total>=s||u===void 0||u===i)break;i=u}return r},broadcastPage:A,list:t=>I(t),register:t=>("token"in t||$(),f.put(Q(t,void 0,{allowedPushOrigins:o.allowedPushOrigins}))),send:async(t,e)=>{const{error:r,receipt:i}=await O(await C(t),e,!0);if(i===void 0)throw new k("INTERNAL",`@lunora/notify: push send failed: ${r??"unknown error"}`);return i},unregister:t=>f.delete(t)},y=async(t,e)=>{if(h.getProvider(t)===void 0)throw N(t,"channel-not-configured"),new k("BAD_REQUEST",`@lunora/notify: the "${t}" channel is not configured in defineNotify(...)`);const r=await h.sendToChannel(t,e),i=r.successful?"accepted":"failed";return w(t,r.provider,i),i==="failed"&&v(t,r.provider,{error:b(r)}),r};return{notify:{chat:t=>y("chat",t),inApp:t=>y("inapp",t),push:x,send:async t=>{const e=await h.send(t);for(const r of e){const i=r.channel??"unknown",s=r.successful?"accepted":"failed";w(i,r.provider,s),s==="failed"&&v(i,r.provider,{error:b(r)})}return e},webhook:t=>y("webhook",t)},push:x}};export{V as createNotify};
|
package/dist/web.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const o=r=>{const e="=".repeat((4-r.length%4)%4),s=(r+e).replaceAll("-","+").replaceAll("_","/"),i=atob(s),n=new Uint8Array(i.length);for(let t=0;t<i.length;t+=1)n[t]=i.codePointAt(t)??0;return n},u=(r,e)=>r.length===e.length&&r.every((s,i)=>s===e[i]),c=(r,e)=>{const s=r.options.applicationServerKey;return s===null?!1:u(new Uint8Array(s),o(e))},a=globalThis,l=()=>a.navigator?.serviceWorker!==void 0&&a.PushManager!==void 0,p=async r=>{if(!l())throw new Error("@lunora/notify: Web Push is not supported in this browser (needs service workers + PushManager)");let e;if(r.serviceWorkerUrl===void 0)e=await navigator.serviceWorker.ready;else{const t=r.scope===void 0?void 0:{scope:r.scope};e=await navigator.serviceWorker.register(r.serviceWorkerUrl,t)}const s=await Notification.requestPermission();if(s!=="granted")throw new Error(`@lunora/notify: notification permission was not granted (got "${s}")`);const i=await e.pushManager.getSubscription();let n=null;return i!==null&&(c(i,r.vapidPublicKey)?n=i:await i.unsubscribe()),(n??await e.pushManager.subscribe({applicationServerKey:o(r.vapidPublicKey),userVisibleOnly:!0})).toJSON()},g=async()=>{if(!l())return!1;const r=await(await navigator.serviceWorker.ready).pushManager.getSubscription();return r===null?!1:r.unsubscribe()};export{l as isPushSupported,p as subscribeToPush,g as unsubscribeFromPush};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/notify",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.12",
|
|
4
4
|
"description": "Multi-channel notifications for Lunora — ctx.notify / ctx.push over @visulima/notification: edge-safe Web Push + FCM, plus chat, in-app inbox and webhook channels, with subscription storage and queue-backed fan-out",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
52
|
+
"@lunora/errors": "1.0.0-alpha.15",
|
|
53
53
|
"@visulima/notification": "1.0.5"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createNotification as s}from"@visulima/notification";import{retryMiddleware as a,circuitBreakerMiddleware as c}from"@visulima/notification/middleware";import{fcmProvider as u}from"@visulima/notification/providers/fcm";import{webPushProvider as d}from"@visulima/notification/providers/web-push";const i=e=>{if(typeof e!="string")return typeof e=="object"&&e!==null&&"endpoint"in e;if(!e.startsWith("{"))return!1;try{const t=JSON.parse(e);return typeof t.endpoint=="string"&&typeof t.keys=="object"}catch{return!1}},f=e=>{const t=o=>{const r=i(o)?e.webPush:e.fcm;if(r===void 0)throw new Error(i(o)?"@lunora/notify: received a web-push target but no `webPush` channel is configured":"@lunora/notify: received an FCM token target but no `fcm` channel is configured");return r};return{channel:"push",id:"lunora-push-router",initialize:async()=>{await e.webPush?.initialize(),await e.fcm?.initialize()},isAvailable:()=>(e.webPush??e.fcm)!==void 0,send:o=>{const r=Array.isArray(o.to)?o.to[0]:o.to;return t(r).send(o)}}},w=e=>{const t=e.webPush===void 0?void 0:d(e.webPush),o=e.fcm===void 0?void 0:u(e.fcm),r={};(t!==void 0||o!==void 0)&&(r.push=f({fcm:o,webPush:t})),e.chat!==void 0&&(r.chat=e.chat),e.inApp!==void 0&&(r.inapp=e.inApp),e.webhook!==void 0&&(r.webhook=e.webhook);const n=s(r);return n.use(a()).use(c()),n};export{w as buildEngine,f as routingPushProvider};
|