+41
-2
@@ -1,2 +0,2 @@ | ||
| import { DeviceRegistration, NitroPingConfig, SubscriptionOptions, SubscriptionStatus } from "./types.js"; | ||
| import { DeviceRegistration, IdentifyOptions, NitroPingConfig, PreferenceUpdateOptions, SubscriberPreferenceRecord, SubscriberProfile, SubscriptionOptions, SubscriptionStatus } from "./types.js"; | ||
@@ -25,3 +25,3 @@ //#region src/client.d.ts | ||
| /** | ||
| * Unsubscribes from push notifications | ||
| * Unsubscribes from push notifications and removes the device from the backend | ||
| */ | ||
@@ -38,2 +38,37 @@ unsubscribe(): Promise<boolean>; | ||
| /** | ||
| * Identifies a subscriber (user) in the NitroPing system. | ||
| * If a subscriber with the given externalId already exists it is updated, | ||
| * otherwise a new subscriber is created. | ||
| * | ||
| * @example | ||
| * await client.identify('user-123', { name: 'John', email: 'user@example.com' }) | ||
| */ | ||
| identify(externalId: string, options?: IdentifyOptions): Promise<SubscriberProfile>; | ||
| /** | ||
| * Fetches a contact by external ID. | ||
| */ | ||
| getContact(externalId: string): Promise<SubscriberProfile | null>; | ||
| /** | ||
| * Fetches preferences for a contact by their internal ID. | ||
| */ | ||
| getPreferences(contactId: string): Promise<SubscriberPreferenceRecord[]>; | ||
| /** | ||
| * Tracks a notification event (delivered, opened, clicked). | ||
| */ | ||
| trackEvent(notificationId: string, event: 'delivered' | 'opened' | 'clicked'): Promise<void>; | ||
| /** | ||
| * Updates a subscriber's notification preference for a given category and channel. | ||
| * | ||
| * @example | ||
| * await client.updatePreference({ | ||
| * subscriberId: 'sub-id', | ||
| * category: 'marketing', | ||
| * channelType: 'EMAIL', | ||
| * enabled: false, | ||
| * }) | ||
| */ | ||
| updatePreference(input: PreferenceUpdateOptions & { | ||
| subscriberId: string; | ||
| }): Promise<SubscriberPreferenceRecord>; | ||
| /** | ||
| * Registers a device with the NitroPing backend | ||
@@ -43,2 +78,6 @@ */ | ||
| /** | ||
| * Deletes a device from the backend | ||
| */ | ||
| private deleteDevice; | ||
| /** | ||
| * Gets or generates a user ID | ||
@@ -45,0 +84,0 @@ */ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"client.d.ts","names":[],"sources":["../src/client.ts"],"sourcesContent":[],"mappings":";;;cAwBa,eAAA;;EAAA,QAAA,UAAe;EAAA,WAAA,CAAA,MAAA,EAIN,eAJM;;;;aAqCC,CAAA,CAAA,EAAA,OAAA;;;;qBAyFN,CAAA,CAAA,EAhGE,sBAgGF;;;;EA4CiB,iBAAA,CAAA,CAAA,EArIX,OAqIW,CArIH,sBAqIG,CAAA;;;;sBAtHb,sBAA2B,QAAQ;;;;iBA0EvC;;;;kBAyBC;;;;2BAmBS,QAAQ"} | ||
| {"version":3,"file":"client.d.ts","names":[],"sources":["../src/client.ts"],"mappings":";;;cA4Ba,eAAA;EAAA,QACH,MAAA;EAAA,QACA,UAAA;cAEI,MAAA,EAAQ,eAAA;;;;EAiBpB,WAAA,CAAA;EAc2B;;;EAP3B,mBAAA,CAAA,GAAuB,sBAAA;EAwGF;;;EAjGf,iBAAA,CAAA,GAAqB,OAAA,CAAQ,sBAAA;EA4KS;;;EA7JtC,SAAA,CAAU,OAAA,GAAS,mBAAA,GAA2B,OAAA,CAAQ,kBAAA;EA0MtB;;;EAxHhC,WAAA,CAAA,GAAe,OAAA;EAyNS;;;EApLxB,YAAA,CAAA,GAAgB,OAAA;EAoLoE;;;EAjKpF,qBAAA,CAAA,GAAyB,OAAA,CAAQ,kBAAA;EAxLnB;;;;;;;;EA2Md,QAAA,CAAS,UAAA,UAAoB,OAAA,GAAS,eAAA,GAAuB,OAAA,CAAQ,iBAAA;EA7JlD;;;EA0MnB,UAAA,CAAW,UAAA,WAAqB,OAAA,CAAQ,iBAAA;EAxHxC;;;EA2JA,cAAA,CAAe,SAAA,WAAoB,OAAA,CAAQ,0BAAA;EAnG3C;;;EAmIA,UAAA,CAAW,cAAA,UAAwB,KAAA,uCAA4C,OAAA;EAhHtE;;;;;;;;;;;EA8IT,gBAAA,CAAiB,KAAA,EAAO,uBAAA;IAA4B,YAAA;EAAA,IAAyB,OAAA,CAAQ,0BAAA;EA9B1E;;;EAAA,QAiEH,cAAA;EAnCgB;;;EAAA,QAqFhB,YAAA;EArF6E;;;EAAA,QA2GnF,SAAA;EAYA;;;EAAA,QAAA,iBAAA;EAsBiB;;;EAAA,QAXjB,qBAAA;;;;UAWA,iBAAA;AAAA"} |
+62
-2
@@ -1,2 +0,56 @@ | ||
| import{NitroPingError as e}from"./types.js";import{apiRequest as t,detectBrowser as n,detectOS as r,generateUserId as i,getBrowserVersion as a,getCategoryFromBrowser as o,getLocalStorage as s,getNotificationPermission as c,isPushSupported as l,isSecureContext as u,removeLocalStorage as d,setLocalStorage as f,urlBase64ToUint8Array as p}from"./utils.js";import{_defineProperty as m}from"./node_modules/.pnpm/@oxc-project_runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/esm/defineProperty.js";var h=class{constructor(t){if(m(this,`config`,void 0),m(this,`storageKey`,void 0),this.config={apiUrl:`http://localhost:3000`,...t},this.storageKey=`nitroping_${this.config.appId}`,!this.config.appId)throw new e(`appId is required`,`INVALID_CONFIG`);if(!this.config.vapidPublicKey)throw new e(`vapidPublicKey is required`,`INVALID_CONFIG`)}isSupported(){return l()&&u()}getPermissionStatus(){return c()}async requestPermission(){if(!this.isSupported())throw new e(`Push notifications are not supported in this environment`,`NOT_SUPPORTED`);let t=await Notification.requestPermission();return t}async subscribe(t={}){if(!this.isSupported())throw new e(`Push notifications are not supported in this environment`,`NOT_SUPPORTED`);let i=await this.requestPermission();if(i!==`granted`)throw new e(`Notification permission was denied`,`PERMISSION_DENIED`);let s=await navigator.serviceWorker.register(`/sw.js`);await navigator.serviceWorker.ready;let c=await s.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:p(this.config.vapidPublicKey)}),l={endpoint:c.endpoint,keys:{p256dh:btoa(String.fromCharCode(...new Uint8Array(c.getKey(`p256dh`)))),auth:btoa(String.fromCharCode(...new Uint8Array(c.getKey(`auth`))))}},u=t.userId||this.config.userId||this.getUserId(),d=n(),f=o(d),m=await this.registerDevice({appId:this.config.appId,token:c.endpoint,...f!==`WEB`&&{category:f},platform:`WEB`,userId:u,metadata:JSON.stringify({userAgent:navigator.userAgent,browser:d,browserVersion:a(),os:r(),subscription:l,tags:t.tags||[],...t.metadata})});return this.storeSubscription({subscription:l,device:m,userId:u}),m}async unsubscribe(){try{let e=await navigator.serviceWorker.ready,t=await e.pushManager.getSubscription();return t&&await t.unsubscribe(),this.clearSubscription(),!0}catch(e){return console.error(`Failed to unsubscribe:`,e),!1}}async isSubscribed(){try{if(!this.isSupported())return!1;let e=await navigator.serviceWorker.ready,t=await e.pushManager.getSubscription();return t!==null}catch(e){return console.error(`Failed to check subscription status:`,e),!1}}async getSubscriptionStatus(){let e=await this.isSubscribed(),t=this.getStoredSubscription();return{isSubscribed:e,subscription:t?.subscription,device:t?.device}}async registerDevice(n){let r=await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| import{NitroPingError as e}from"./types.js";import{apiRequest as t,detectBrowser as n,detectOS as r,generateUserId as i,getBrowserVersion as a,getCategoryFromBrowser as o,getLocalStorage as s,getNotificationPermission as c,isPushSupported as l,isSecureContext as u,removeLocalStorage as d,setLocalStorage as f,urlBase64ToUint8Array as p}from"./utils.js";var m=class{constructor(t){if(this.config={apiUrl:`http://localhost:3000`,...t},this.storageKey=`nitroping_${this.config.appId}`,!this.config.appId)throw new e(`appId is required`,`INVALID_CONFIG`)}isSupported(){return l()&&u()}getPermissionStatus(){return c()}async requestPermission(){if(!this.isSupported())throw new e(`Push notifications are not supported in this environment`,`NOT_SUPPORTED`);return await Notification.requestPermission()}async subscribe(t={}){if(!this.isSupported())throw new e(`Push notifications are not supported in this environment`,`NOT_SUPPORTED`);if(!this.config.vapidPublicKey)throw new e(`vapidPublicKey is required for push subscriptions`,`INVALID_CONFIG`);if(await this.requestPermission()!==`granted`)throw new e(`Notification permission was denied`,`PERMISSION_DENIED`);let i=this.config.swPath??`/sw.js`,s=await navigator.serviceWorker.register(i);await navigator.serviceWorker.ready;let c=await s.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:p(this.config.vapidPublicKey)}),l={endpoint:c.endpoint,keys:{p256dh:btoa(String.fromCharCode(...new Uint8Array(c.getKey(`p256dh`)))),auth:btoa(String.fromCharCode(...new Uint8Array(c.getKey(`auth`))))}},u=t.userId||this.config.userId||this.getUserId(),d=n(),f=o(d),m=await this.registerDevice({appId:this.config.appId,token:c.endpoint,...f!==`WEB`&&{category:f},platform:`WEB`,userId:u,webPushP256dh:l.keys.p256dh,webPushAuth:l.keys.auth,metadata:JSON.stringify({userAgent:navigator.userAgent,browser:d,browserVersion:a(),os:r(),tags:t.tags||[],...t.metadata})});return this.storeSubscription({subscription:l,device:m,userId:u}),m}async unsubscribe(){try{let e=await(await navigator.serviceWorker.ready).pushManager.getSubscription(),t=this.getStoredSubscription();if(e&&await e.unsubscribe(),t?.device?.id)try{await this.deleteDevice(t.device.id)}catch{}return this.clearSubscription(),!0}catch(e){return console.error(`Failed to unsubscribe:`,e),!1}}async isSubscribed(){try{return this.isSupported()?await(await navigator.serviceWorker.ready).pushManager.getSubscription()!==null:!1}catch(e){return console.error(`Failed to check subscription status:`,e),!1}}async getSubscriptionStatus(){let e=await this.isSubscribed(),t=this.getStoredSubscription();return{isSubscribed:e,subscription:t?.subscription,device:t?.device}}async identify(n,r={}){let i=await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| mutation CreateContact($input: CreateContactInput!) { | ||
| createContact(input: $input) { | ||
| id | ||
| appId | ||
| externalId | ||
| name | ||
| phone | ||
| locale | ||
| metadata | ||
| createdAt | ||
| updatedAt | ||
| } | ||
| } | ||
| `,variables:{input:{appId:this.config.appId,externalId:n,...r}}})});if(!i.data?.createContact)throw new e(`Failed to identify subscriber`,`IDENTIFY_FAILED`);return i.data.createContact}async getContact(e){return(await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| query GetContact($appId: ID!, $externalId: String!) { | ||
| contactByExternalId(appId: $appId, externalId: $externalId) { | ||
| id | ||
| appId | ||
| externalId | ||
| name | ||
| phone | ||
| locale | ||
| metadata | ||
| createdAt | ||
| updatedAt | ||
| } | ||
| } | ||
| `,variables:{appId:this.config.appId,externalId:e}})})).data?.contactByExternalId??null}async getPreferences(e){return(await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| query GetContact($id: ID!) { | ||
| contact(id: $id) { | ||
| preferences { | ||
| id | ||
| subscriberId | ||
| category | ||
| channelType | ||
| enabled | ||
| updatedAt | ||
| } | ||
| } | ||
| } | ||
| `,variables:{id:e}})})).data?.contact?.preferences??[]}async trackEvent(e,n){let r={delivered:`mutation { trackNotificationDelivered(notificationId: "${e}") }`,opened:`mutation { trackNotificationOpened(notificationId: "${e}") }`,clicked:`mutation { trackNotificationClicked(notificationId: "${e}") }`}[n];r&&await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:r})})}async updatePreference(n){let r=await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| mutation UpdateContactPreference($input: UpdateContactPreferenceInput!) { | ||
| updateContactPreference(input: $input) { | ||
| id | ||
| subscriberId | ||
| category | ||
| channelType | ||
| enabled | ||
| updatedAt | ||
| } | ||
| } | ||
| `,variables:{input:n}})});if(!r.data?.updateContactPreference)throw new e(`Failed to update preference`,`PREFERENCE_UPDATE_FAILED`);return r.data.updateContactPreference}async registerDevice(n){let r=await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| mutation RegisterDevice($input: RegisterDeviceInput!) { | ||
@@ -9,2 +63,4 @@ registerDevice(input: $input) { | ||
| userId | ||
| webPushP256dh | ||
| webPushAuth | ||
| metadata | ||
@@ -17,3 +73,7 @@ status | ||
| } | ||
| `,variables:{input:n}})});if(!r.data?.registerDevice)throw new e(`Failed to register device`,`REGISTRATION_FAILED`);return r.data.registerDevice}getUserId(){let e=s(`${this.storageKey}_userId`);return e||(e=i(),f(`${this.storageKey}_userId`,e)),e}storeSubscription(e){f(this.storageKey,e)}getStoredSubscription(){return s(this.storageKey)}clearSubscription(){d(this.storageKey)}};export{h as NitroPingClient}; | ||
| `,variables:{input:n}})});if(!r.data?.registerDevice)throw new e(`Failed to register device`,`REGISTRATION_FAILED`);return r.data.registerDevice}async deleteDevice(e){await t(`${this.config.apiUrl}/api/graphql`,{method:`POST`,body:JSON.stringify({query:` | ||
| mutation DeleteDevice($id: ID!) { | ||
| deleteDevice(id: $id) | ||
| } | ||
| `,variables:{id:e}})})}getUserId(){let e=s(`${this.storageKey}_userId`);return e||(e=i(),f(`${this.storageKey}_userId`,e)),e}storeSubscription(e){f(this.storageKey,e)}getStoredSubscription(){return s(this.storageKey)}clearSubscription(){d(this.storageKey)}};export{m as NitroPingClient}; | ||
| //# sourceMappingURL=client.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"client.js","names":["subscriptionData: PushSubscriptionData"],"sources":["../src/client.ts"],"sourcesContent":["import type {\n DeviceRegistration,\n NitroPingConfig,\n PushSubscriptionData,\n SubscriptionOptions,\n SubscriptionStatus,\n} from './types.ts'\nimport { NitroPingError } from './types.ts'\nimport {\n apiRequest,\n detectBrowser,\n detectOS,\n generateUserId,\n getBrowserVersion,\n getCategoryFromBrowser,\n getLocalStorage,\n getNotificationPermission,\n isPushSupported,\n isSecureContext,\n removeLocalStorage,\n setLocalStorage,\n urlBase64ToUint8Array,\n} from './utils.ts'\n\nexport class NitroPingClient {\n private config: NitroPingConfig\n private storageKey: string\n\n constructor(config: NitroPingConfig) {\n this.config = {\n apiUrl: 'http://localhost:3000',\n ...config,\n }\n this.storageKey = `nitroping_${this.config.appId}`\n\n // Validate required config\n if (!this.config.appId) {\n throw new NitroPingError('appId is required', 'INVALID_CONFIG')\n }\n if (!this.config.vapidPublicKey) {\n throw new NitroPingError('vapidPublicKey is required', 'INVALID_CONFIG')\n }\n }\n\n /**\n * Checks if push notifications are supported in the current environment\n */\n isSupported(): boolean {\n return isPushSupported() && isSecureContext()\n }\n\n /**\n * Gets the current notification permission status\n */\n getPermissionStatus(): NotificationPermission {\n return getNotificationPermission()\n }\n\n /**\n * Requests notification permission from the user\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n throw new NitroPingError(\n 'Push notifications are not supported in this environment',\n 'NOT_SUPPORTED',\n )\n }\n\n const permission = await Notification.requestPermission()\n return permission\n }\n\n /**\n * Subscribes to push notifications\n */\n async subscribe(options: SubscriptionOptions = {}): Promise<DeviceRegistration> {\n if (!this.isSupported()) {\n throw new NitroPingError(\n 'Push notifications are not supported in this environment',\n 'NOT_SUPPORTED',\n )\n }\n\n // Request permission if not already granted\n const permission = await this.requestPermission()\n if (permission !== 'granted') {\n throw new NitroPingError(\n 'Notification permission was denied',\n 'PERMISSION_DENIED',\n )\n }\n\n // Register service worker\n const registration = await navigator.serviceWorker.register('/sw.js')\n await navigator.serviceWorker.ready\n\n // Subscribe to push notifications\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlBase64ToUint8Array(this.config.vapidPublicKey),\n })\n\n // Prepare subscription data\n const subscriptionData: PushSubscriptionData = {\n endpoint: subscription.endpoint,\n keys: {\n p256dh: btoa(String.fromCharCode(...new Uint8Array(subscription.getKey('p256dh')!))),\n auth: btoa(String.fromCharCode(...new Uint8Array(subscription.getKey('auth')!))),\n },\n }\n\n // Get or generate user ID\n const userId = options.userId || this.config.userId || this.getUserId()\n\n // Register device with backend\n const browserType = detectBrowser()\n const category = getCategoryFromBrowser(browserType)\n\n const device = await this.registerDevice({\n appId: this.config.appId,\n token: subscription.endpoint,\n // Only set category for known browsers, otherwise null\n ...(category !== 'WEB' && { category }),\n platform: 'WEB',\n userId,\n metadata: JSON.stringify({\n userAgent: navigator.userAgent,\n browser: browserType,\n browserVersion: getBrowserVersion(),\n os: detectOS(),\n subscription: subscriptionData,\n tags: options.tags || [],\n ...options.metadata,\n }),\n })\n\n // Store subscription locally\n this.storeSubscription({\n subscription: subscriptionData,\n device,\n userId,\n })\n\n return device\n }\n\n /**\n * Unsubscribes from push notifications\n */\n async unsubscribe(): Promise<boolean> {\n try {\n // Get current subscription\n const registration = await navigator.serviceWorker.ready\n const subscription = await registration.pushManager.getSubscription()\n\n if (subscription) {\n // Unsubscribe from push manager\n await subscription.unsubscribe()\n }\n\n // Remove from local storage\n this.clearSubscription()\n\n return true\n }\n catch (error) {\n console.error('Failed to unsubscribe:', error)\n return false\n }\n }\n\n /**\n * Checks if the user is currently subscribed\n */\n async isSubscribed(): Promise<boolean> {\n try {\n if (!this.isSupported())\n return false\n\n const registration = await navigator.serviceWorker.ready\n const subscription = await registration.pushManager.getSubscription()\n\n return subscription !== null\n }\n catch (error) {\n console.error('Failed to check subscription status:', error)\n return false\n }\n }\n\n /**\n * Gets the current subscription status and details\n */\n async getSubscriptionStatus(): Promise<SubscriptionStatus> {\n const isSubscribed = await this.isSubscribed()\n const stored = this.getStoredSubscription()\n\n return {\n isSubscribed,\n subscription: stored?.subscription,\n device: stored?.device,\n }\n }\n\n /**\n * Registers a device with the NitroPing backend\n */\n private async registerDevice(input: {\n appId: string\n token: string\n category?: string\n platform: string\n userId: string\n metadata: string\n }): Promise<DeviceRegistration> {\n const query = `\n mutation RegisterDevice($input: RegisterDeviceInput!) {\n registerDevice(input: $input) {\n id\n appId\n token\n platform\n userId\n metadata\n status\n lastSeenAt\n createdAt\n updatedAt\n }\n }\n `\n\n const response = await apiRequest<{ data: { registerDevice: DeviceRegistration } }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: { input },\n }),\n },\n )\n\n if (!response.data?.registerDevice) {\n throw new NitroPingError('Failed to register device', 'REGISTRATION_FAILED')\n }\n\n return response.data.registerDevice\n }\n\n /**\n * Gets or generates a user ID\n */\n private getUserId(): string {\n let userId = getLocalStorage<string>(`${this.storageKey}_userId`)\n if (!userId) {\n userId = generateUserId()\n setLocalStorage(`${this.storageKey}_userId`, userId)\n }\n return userId\n }\n\n /**\n * Stores subscription data locally\n */\n private storeSubscription(data: {\n subscription: PushSubscriptionData\n device: DeviceRegistration\n userId: string\n }): void {\n setLocalStorage(this.storageKey, data)\n }\n\n /**\n * Gets stored subscription data\n */\n private getStoredSubscription(): {\n subscription: PushSubscriptionData\n device: DeviceRegistration\n userId: string\n } | null {\n return getLocalStorage(this.storageKey)\n }\n\n /**\n * Clears stored subscription data\n */\n private clearSubscription(): void {\n removeLocalStorage(this.storageKey)\n }\n}\n"],"mappings":"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"} | ||
| {"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type {\n DeviceRegistration,\n IdentifyOptions,\n NitroPingConfig,\n PreferenceUpdateOptions,\n PushSubscriptionData,\n SubscriberPreferenceRecord,\n SubscriberProfile,\n SubscriptionOptions,\n SubscriptionStatus,\n} from './types.ts'\nimport { NitroPingError } from './types.ts'\nimport {\n apiRequest,\n detectBrowser,\n detectOS,\n generateUserId,\n getBrowserVersion,\n getCategoryFromBrowser,\n getLocalStorage,\n getNotificationPermission,\n isPushSupported,\n isSecureContext,\n removeLocalStorage,\n setLocalStorage,\n urlBase64ToUint8Array,\n} from './utils.ts'\n\nexport class NitroPingClient {\n private config: NitroPingConfig\n private storageKey: string\n\n constructor(config: NitroPingConfig) {\n this.config = {\n apiUrl: 'http://localhost:3000',\n ...config,\n }\n this.storageKey = `nitroping_${this.config.appId}`\n\n // Validate required config\n if (!this.config.appId) {\n throw new NitroPingError('appId is required', 'INVALID_CONFIG')\n }\n // vapidPublicKey is only required when subscribe() is called, not at construction\n }\n\n /**\n * Checks if push notifications are supported in the current environment\n */\n isSupported(): boolean {\n return isPushSupported() && isSecureContext()\n }\n\n /**\n * Gets the current notification permission status\n */\n getPermissionStatus(): NotificationPermission {\n return getNotificationPermission()\n }\n\n /**\n * Requests notification permission from the user\n */\n async requestPermission(): Promise<NotificationPermission> {\n if (!this.isSupported()) {\n throw new NitroPingError(\n 'Push notifications are not supported in this environment',\n 'NOT_SUPPORTED',\n )\n }\n\n const permission = await Notification.requestPermission()\n return permission\n }\n\n /**\n * Subscribes to push notifications\n */\n async subscribe(options: SubscriptionOptions = {}): Promise<DeviceRegistration> {\n if (!this.isSupported()) {\n throw new NitroPingError(\n 'Push notifications are not supported in this environment',\n 'NOT_SUPPORTED',\n )\n }\n\n // vapidPublicKey is required for push subscriptions\n if (!this.config.vapidPublicKey) {\n throw new NitroPingError('vapidPublicKey is required for push subscriptions', 'INVALID_CONFIG')\n }\n\n // Request permission if not already granted\n const permission = await this.requestPermission()\n if (permission !== 'granted') {\n throw new NitroPingError(\n 'Notification permission was denied',\n 'PERMISSION_DENIED',\n )\n }\n\n // Register service worker\n const swPath = this.config.swPath ?? '/sw.js'\n const registration = await navigator.serviceWorker.register(swPath)\n await navigator.serviceWorker.ready\n\n // Subscribe to push notifications\n const subscription = await registration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: urlBase64ToUint8Array(this.config.vapidPublicKey),\n })\n\n // Prepare subscription data\n const subscriptionData: PushSubscriptionData = {\n endpoint: subscription.endpoint,\n keys: {\n p256dh: btoa(String.fromCharCode(...new Uint8Array(subscription.getKey('p256dh')!))),\n auth: btoa(String.fromCharCode(...new Uint8Array(subscription.getKey('auth')!))),\n },\n }\n\n // Get or generate user ID\n const userId = options.userId || this.config.userId || this.getUserId()\n\n // Register device with backend\n const browserType = detectBrowser()\n const category = getCategoryFromBrowser(browserType)\n\n const device = await this.registerDevice({\n appId: this.config.appId,\n token: subscription.endpoint,\n // Only set category for known browsers, otherwise null\n ...(category !== 'WEB' && { category }),\n platform: 'WEB',\n userId,\n // WebPush subscription keys for encryption\n webPushP256dh: subscriptionData.keys.p256dh,\n webPushAuth: subscriptionData.keys.auth,\n metadata: JSON.stringify({\n userAgent: navigator.userAgent,\n browser: browserType,\n browserVersion: getBrowserVersion(),\n os: detectOS(),\n tags: options.tags || [],\n ...options.metadata,\n }),\n })\n\n // Store subscription locally\n this.storeSubscription({\n subscription: subscriptionData,\n device,\n userId,\n })\n\n return device\n }\n\n /**\n * Unsubscribes from push notifications and removes the device from the backend\n */\n async unsubscribe(): Promise<boolean> {\n try {\n // Get current subscription\n const registration = await navigator.serviceWorker.ready\n const subscription = await registration.pushManager.getSubscription()\n\n const stored = this.getStoredSubscription()\n\n if (subscription) {\n // Unsubscribe from push manager\n await subscription.unsubscribe()\n }\n\n // Delete device from backend if we have a device ID\n if (stored?.device?.id) {\n try {\n await this.deleteDevice(stored.device.id)\n }\n catch {\n // Best-effort — do not fail unsubscribe if backend call fails\n }\n }\n\n // Remove from local storage\n this.clearSubscription()\n\n return true\n }\n catch (error) {\n console.error('Failed to unsubscribe:', error)\n return false\n }\n }\n\n /**\n * Checks if the user is currently subscribed\n */\n async isSubscribed(): Promise<boolean> {\n try {\n if (!this.isSupported())\n return false\n\n const registration = await navigator.serviceWorker.ready\n const subscription = await registration.pushManager.getSubscription()\n\n return subscription !== null\n }\n catch (error) {\n console.error('Failed to check subscription status:', error)\n return false\n }\n }\n\n /**\n * Gets the current subscription status and details\n */\n async getSubscriptionStatus(): Promise<SubscriptionStatus> {\n const isSubscribed = await this.isSubscribed()\n const stored = this.getStoredSubscription()\n\n return {\n isSubscribed,\n subscription: stored?.subscription,\n device: stored?.device,\n }\n }\n\n /**\n * Identifies a subscriber (user) in the NitroPing system.\n * If a subscriber with the given externalId already exists it is updated,\n * otherwise a new subscriber is created.\n *\n * @example\n * await client.identify('user-123', { name: 'John', email: 'user@example.com' })\n */\n async identify(externalId: string, options: IdentifyOptions = {}): Promise<SubscriberProfile> {\n const query = `\n mutation CreateContact($input: CreateContactInput!) {\n createContact(input: $input) {\n id\n appId\n externalId\n name\n email\n phone\n locale\n metadata\n createdAt\n updatedAt\n }\n }\n `\n\n const response = await apiRequest<{ data: { createContact: SubscriberProfile } }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: {\n input: {\n appId: this.config.appId,\n externalId,\n ...options,\n },\n },\n }),\n },\n )\n\n if (!response.data?.createContact) {\n throw new NitroPingError('Failed to identify subscriber', 'IDENTIFY_FAILED')\n }\n\n return response.data.createContact\n }\n\n /**\n * Fetches a contact by external ID.\n */\n async getContact(externalId: string): Promise<SubscriberProfile | null> {\n const query = `\n query GetContact($appId: ID!, $externalId: String!) {\n contactByExternalId(appId: $appId, externalId: $externalId) {\n id\n appId\n externalId\n name\n email\n phone\n locale\n metadata\n createdAt\n updatedAt\n }\n }\n `\n\n const response = await apiRequest<{ data: { contactByExternalId: SubscriberProfile | null } }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: { appId: this.config.appId, externalId },\n }),\n },\n )\n\n return response.data?.contactByExternalId ?? null\n }\n\n /**\n * Fetches preferences for a contact by their internal ID.\n */\n async getPreferences(contactId: string): Promise<SubscriberPreferenceRecord[]> {\n const query = `\n query GetContact($id: ID!) {\n contact(id: $id) {\n preferences {\n id\n subscriberId\n category\n channelType\n enabled\n updatedAt\n }\n }\n }\n `\n\n const response = await apiRequest<{\n data: { contact: { preferences: SubscriberPreferenceRecord[] } | null }\n }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({ query, variables: { id: contactId } }),\n },\n )\n\n return response.data?.contact?.preferences ?? []\n }\n\n /**\n * Tracks a notification event (delivered, opened, clicked).\n */\n async trackEvent(notificationId: string, event: 'delivered' | 'opened' | 'clicked'): Promise<void> {\n const mutationMap: Record<string, string> = {\n delivered: `mutation { trackNotificationDelivered(notificationId: \"${notificationId}\") }`,\n opened: `mutation { trackNotificationOpened(notificationId: \"${notificationId}\") }`,\n clicked: `mutation { trackNotificationClicked(notificationId: \"${notificationId}\") }`,\n }\n\n const query = mutationMap[event]\n if (!query) return\n\n await apiRequest(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({ query }),\n },\n )\n }\n\n /**\n * Updates a subscriber's notification preference for a given category and channel.\n *\n * @example\n * await client.updatePreference({\n * subscriberId: 'sub-id',\n * category: 'marketing',\n * channelType: 'EMAIL',\n * enabled: false,\n * })\n */\n async updatePreference(input: PreferenceUpdateOptions & { subscriberId: string }): Promise<SubscriberPreferenceRecord> {\n const query = `\n mutation UpdateContactPreference($input: UpdateContactPreferenceInput!) {\n updateContactPreference(input: $input) {\n id\n subscriberId\n category\n channelType\n enabled\n updatedAt\n }\n }\n `\n\n const response = await apiRequest<{ data: { updateContactPreference: SubscriberPreferenceRecord } }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: { input },\n }),\n },\n )\n\n if (!response.data?.updateContactPreference) {\n throw new NitroPingError('Failed to update preference', 'PREFERENCE_UPDATE_FAILED')\n }\n\n return response.data.updateContactPreference\n }\n\n /**\n * Registers a device with the NitroPing backend\n */\n private async registerDevice(input: {\n appId: string\n token: string\n category?: string\n platform: string\n userId: string\n webPushP256dh: string\n webPushAuth: string\n metadata: string\n }): Promise<DeviceRegistration> {\n const query = `\n mutation RegisterDevice($input: RegisterDeviceInput!) {\n registerDevice(input: $input) {\n id\n appId\n token\n platform\n userId\n webPushP256dh\n webPushAuth\n metadata\n status\n lastSeenAt\n createdAt\n updatedAt\n }\n }\n `\n\n const response = await apiRequest<{ data: { registerDevice: DeviceRegistration } }>(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: { input },\n }),\n },\n )\n\n if (!response.data?.registerDevice) {\n throw new NitroPingError('Failed to register device', 'REGISTRATION_FAILED')\n }\n\n return response.data.registerDevice\n }\n\n /**\n * Deletes a device from the backend\n */\n private async deleteDevice(deviceId: string): Promise<void> {\n const query = `\n mutation DeleteDevice($id: ID!) {\n deleteDevice(id: $id)\n }\n `\n\n await apiRequest(\n `${this.config.apiUrl}/api/graphql`,\n {\n method: 'POST',\n body: JSON.stringify({\n query,\n variables: { id: deviceId },\n }),\n },\n )\n }\n\n /**\n * Gets or generates a user ID\n */\n private getUserId(): string {\n let userId = getLocalStorage<string>(`${this.storageKey}_userId`)\n if (!userId) {\n userId = generateUserId()\n setLocalStorage(`${this.storageKey}_userId`, userId)\n }\n return userId\n }\n\n /**\n * Stores subscription data locally\n */\n private storeSubscription(data: {\n subscription: PushSubscriptionData\n device: DeviceRegistration\n userId: string\n }): void {\n setLocalStorage(this.storageKey, data)\n }\n\n /**\n * Gets stored subscription data\n */\n private getStoredSubscription(): {\n subscription: PushSubscriptionData\n device: DeviceRegistration\n userId: string\n } | null {\n return getLocalStorage(this.storageKey)\n }\n\n /**\n * Clears stored subscription data\n */\n private clearSubscription(): void {\n removeLocalStorage(this.storageKey)\n }\n}\n"],"mappings":"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"} |
+2
-2
@@ -1,4 +0,4 @@ | ||
| import { APIResponse, DeviceRegistration, NitroPingConfig, NitroPingError, NotificationAction, NotificationPayload, PushSubscriptionData, SubscriptionOptions, SubscriptionStatus } from "./types.js"; | ||
| import { APIResponse, DeviceRegistration, IdentifyOptions, NitroPingConfig, NitroPingError, NotificationAction, NotificationPayload, PreferenceUpdateOptions, PushSubscriptionData, SubscriberPreferenceRecord, SubscriberProfile, SubscriptionOptions, SubscriptionStatus } from "./types.js"; | ||
| import { NitroPingClient } from "./client.js"; | ||
| import { detectBrowser, detectOS, generateUserId, getBrowserVersion, getNotificationPermission, isPushSupported, isSecureContext, urlBase64ToUint8Array } from "./utils.js"; | ||
| export { type APIResponse, type DeviceRegistration, NitroPingClient, type NitroPingConfig, NitroPingError, type NotificationAction, type NotificationPayload, type PushSubscriptionData, type SubscriptionOptions, type SubscriptionStatus, detectBrowser, detectOS, generateUserId, getBrowserVersion, getNotificationPermission, isPushSupported, isSecureContext, urlBase64ToUint8Array }; | ||
| export { type APIResponse, type DeviceRegistration, type IdentifyOptions, NitroPingClient, type NitroPingConfig, NitroPingError, type NotificationAction, type NotificationPayload, type PreferenceUpdateOptions, type PushSubscriptionData, type SubscriberPreferenceRecord, type SubscriberProfile, type SubscriptionOptions, type SubscriptionStatus, detectBrowser, detectOS, generateUserId, getBrowserVersion, getNotificationPermission, isPushSupported, isSecureContext, urlBase64ToUint8Array }; |
+37
-2
| //#region src/types.d.ts | ||
| interface NitroPingConfig { | ||
| appId: string; | ||
| vapidPublicKey: string; | ||
| vapidPublicKey?: string; | ||
| apiUrl?: string; | ||
| userId?: string; | ||
| swPath?: string; | ||
| } | ||
| interface SubscriberProfile { | ||
| id: string; | ||
| appId: string; | ||
| externalId: string; | ||
| name?: string; | ||
| email?: string; | ||
| phone?: string; | ||
| locale?: string; | ||
| metadata?: Record<string, any>; | ||
| createdAt: string; | ||
| updatedAt: string; | ||
| } | ||
| interface IdentifyOptions { | ||
| name?: string; | ||
| email?: string; | ||
| phone?: string; | ||
| locale?: string; | ||
| metadata?: Record<string, any>; | ||
| } | ||
| interface PreferenceUpdateOptions { | ||
| category: string; | ||
| channelType: 'PUSH' | 'EMAIL' | 'SMS' | 'IN_APP' | 'DISCORD'; | ||
| enabled: boolean; | ||
| } | ||
| interface SubscriberPreferenceRecord { | ||
| id: string; | ||
| subscriberId: string; | ||
| category: string; | ||
| channelType: string; | ||
| enabled: boolean; | ||
| updatedAt: string; | ||
| } | ||
| interface SubscriptionOptions { | ||
@@ -26,2 +59,4 @@ userId?: string; | ||
| userId?: string; | ||
| webPushP256dh?: string; | ||
| webPushAuth?: string; | ||
| metadata?: string; | ||
@@ -70,3 +105,3 @@ status: 'ACTIVE' | 'INACTIVE'; | ||
| //#endregion | ||
| export { APIResponse, DeviceRegistration, NitroPingConfig, NitroPingError, NotificationAction, NotificationPayload, PushSubscriptionData, SubscriptionOptions, SubscriptionStatus }; | ||
| export { APIResponse, DeviceRegistration, IdentifyOptions, NitroPingConfig, NitroPingError, NotificationAction, NotificationPayload, PreferenceUpdateOptions, PushSubscriptionData, SubscriberPreferenceRecord, SubscriberProfile, SubscriptionOptions, SubscriptionStatus }; | ||
| //# sourceMappingURL=types.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";UAAiB,eAAA;EAAA,KAAA,EAAA,MAAA;EAOA,cAAA,EAAA,MAAmB;EAMnB,MAAA,CAAA,EAAA,MAAA;EAQA,MAAA,CAAA,EAAA,MAAA;AAajB;AAiBiB,UA5CA,mBAAA,CA4CkB;EAMlB,MAAA,CAAA,EAAA,MAAW;EAMX,IAAA,CAAA,EAAA,MAAA,EAAA;EAAkB,QAAA,CAAA,EArDtB,MAqDsB,CAAA,MAAA,EAAA,GAAA,CAAA;;AAGxB,UArDM,oBAAA,CAqDN;EAAkB,QAAA,EAAA,MAAA;EAGhB,IAAA,EAAA;;;;;UAhDI,kBAAA;;;;;;;;;;;;UAaA,mBAAA;;;;;;;;YAQL;;;;;;;;UASK,kBAAA;;;;;UAMA;SACR;;;;UAKQ,kBAAA;;iBAEA;WACN;;cAGE,cAAA,SAAuB,KAAA"} | ||
| {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";UAAiB,eAAA;EACf,KAAA;EACA,cAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;AAAA;AAAA,UAKe,iBAAA;EACf,EAAA;EACA,KAAA;EACA,UAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA;EACA,MAAA;EACA,QAAA,GAAW,MAAA;EACX,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,eAAA;EACf,IAAA;EACA,KAAA;EACA,KAAA;EACA,MAAA;EACA,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,uBAAA;EACf,QAAA;EACA,WAAA;EACA,OAAA;AAAA;AAAA,UAGe,0BAAA;EACf,EAAA;EACA,YAAA;EACA,QAAA;EACA,WAAA;EACA,OAAA;EACA,SAAA;AAAA;AAAA,UAGe,mBAAA;EACf,MAAA;EACA,IAAA;EACA,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,oBAAA;EACf,QAAA;EACA,IAAA;IACE,MAAA;IACA,IAAA;EAAA;AAAA;AAAA,UAIa,kBAAA;EACf,EAAA;EACA,KAAA;EACA,KAAA;EACA,QAAA;EACA,MAAA;EACA,aAAA;EACA,WAAA;EACA,QAAA;EACA,MAAA;EACA,UAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,mBAAA;EACf,KAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA;EACA,GAAA;EACA,IAAA;EACA,OAAA,GAAU,kBAAA;EACV,MAAA;EACA,QAAA;EACA,kBAAA;EACA,SAAA;EACA,OAAA;EACA,KAAA;AAAA;AAAA,UAGe,kBAAA;EACf,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,UAGe,WAAA;EACf,IAAA,GAAO,CAAA;EACP,KAAA;EACA,UAAA;AAAA;AAAA,UAGe,kBAAA;EACf,YAAA;EACA,YAAA,GAAe,oBAAA;EACf,MAAA,GAAS,kBAAA;AAAA;AAAA,cAGE,cAAA,SAAuB,KAAA;EAGzB,IAAA;EACA,UAAA;cAFP,OAAA,UACO,IAAA,uBACA,UAAA;AAAA"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"types.js","names":["code?: string","statusCode?: number"],"sources":["../src/types.ts"],"sourcesContent":["export interface NitroPingConfig {\n appId: string\n vapidPublicKey: string\n apiUrl?: string\n userId?: string\n}\n\nexport interface SubscriptionOptions {\n userId?: string\n tags?: string[]\n metadata?: Record<string, any>\n}\n\nexport interface PushSubscriptionData {\n endpoint: string\n keys: {\n p256dh: string\n auth: string\n }\n}\n\nexport interface DeviceRegistration {\n id: string\n appId: string\n token: string\n platform: 'WEB'\n userId?: string\n metadata?: string\n status: 'ACTIVE' | 'INACTIVE'\n lastSeenAt: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface NotificationPayload {\n title: string\n body: string\n icon?: string\n image?: string\n badge?: string\n tag?: string\n data?: any\n actions?: NotificationAction[]\n silent?: boolean\n renotify?: boolean\n requireInteraction?: boolean\n timestamp?: number\n vibrate?: number[]\n sound?: string\n}\n\nexport interface NotificationAction {\n action: string\n title: string\n icon?: string\n}\n\nexport interface APIResponse<T = any> {\n data?: T\n error?: string\n statusCode?: number\n}\n\nexport interface SubscriptionStatus {\n isSubscribed: boolean\n subscription?: PushSubscriptionData\n device?: DeviceRegistration\n}\n\nexport class NitroPingError extends Error {\n constructor(\n message: string,\n public code?: string,\n public statusCode?: number,\n ) {\n super(message)\n this.name = 'NitroPingError'\n }\n}\n"],"mappings":"AAqEA,IAAa,EAAb,cAAoC,KAAM,CACxC,YACE,EACA,EACA,EACA,CACA,MAAM,GAHC,KAAA,KAAA,EACA,KAAA,WAAA,EAGP,KAAK,KAAO,gBACb,CACF"} | ||
| {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["export interface NitroPingConfig {\n appId: string\n vapidPublicKey?: string // required for push subscriptions, optional for email/sms-only usage\n apiUrl?: string\n userId?: string\n swPath?: string // custom service worker path, default: '/sw.js'\n}\n\n// ── Subscriber / multi-channel types ─────────────────────────────────────────\n\nexport interface SubscriberProfile {\n id: string\n appId: string\n externalId: string\n name?: string\n email?: string\n phone?: string\n locale?: string\n metadata?: Record<string, any>\n createdAt: string\n updatedAt: string\n}\n\nexport interface IdentifyOptions {\n name?: string\n email?: string\n phone?: string\n locale?: string\n metadata?: Record<string, any>\n}\n\nexport interface PreferenceUpdateOptions {\n category: string\n channelType: 'PUSH' | 'EMAIL' | 'SMS' | 'IN_APP' | 'DISCORD'\n enabled: boolean\n}\n\nexport interface SubscriberPreferenceRecord {\n id: string\n subscriberId: string\n category: string\n channelType: string\n enabled: boolean\n updatedAt: string\n}\n\nexport interface SubscriptionOptions {\n userId?: string\n tags?: string[]\n metadata?: Record<string, any>\n}\n\nexport interface PushSubscriptionData {\n endpoint: string\n keys: {\n p256dh: string\n auth: string\n }\n}\n\nexport interface DeviceRegistration {\n id: string\n appId: string\n token: string\n platform: 'WEB'\n userId?: string\n webPushP256dh?: string\n webPushAuth?: string\n metadata?: string\n status: 'ACTIVE' | 'INACTIVE'\n lastSeenAt: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface NotificationPayload {\n title: string\n body: string\n icon?: string\n image?: string\n badge?: string\n tag?: string\n data?: any\n actions?: NotificationAction[]\n silent?: boolean\n renotify?: boolean\n requireInteraction?: boolean\n timestamp?: number\n vibrate?: number[]\n sound?: string\n}\n\nexport interface NotificationAction {\n action: string\n title: string\n icon?: string\n}\n\nexport interface APIResponse<T = any> {\n data?: T\n error?: string\n statusCode?: number\n}\n\nexport interface SubscriptionStatus {\n isSubscribed: boolean\n subscription?: PushSubscriptionData\n device?: DeviceRegistration\n}\n\nexport class NitroPingError extends Error {\n constructor(\n message: string,\n public code?: string,\n public statusCode?: number,\n ) {\n super(message)\n this.name = 'NitroPingError'\n }\n}\n"],"mappings":"AA8GA,IAAa,EAAb,cAAoC,KAAM,CACxC,YACE,EACA,EACA,EACA,CACA,MAAM,EAAQ,CAHP,KAAA,KAAA,EACA,KAAA,WAAA,EAGP,KAAK,KAAO"} |
+0
-7
@@ -23,6 +23,2 @@ //#region src/utils.d.ts | ||
| /** | ||
| * Makes an HTTP request to the NitroPing API | ||
| */ | ||
| /** | ||
| * Detects the browser type from user agent | ||
@@ -39,7 +35,4 @@ */ | ||
| declare function getBrowserVersion(): string; | ||
| /** | ||
| * Maps browser type to category enum value (only for supported browsers) | ||
| */ | ||
| //#endregion | ||
| export { detectBrowser, detectOS, generateUserId, getBrowserVersion, getNotificationPermission, isPushSupported, isSecureContext, urlBase64ToUint8Array }; | ||
| //# sourceMappingURL=utils.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"utils.d.ts","names":[],"sources":["../src/utils.ts"],"sourcesContent":[],"mappings":";;AAKA;AAmBA;AAOgB,iBA1BA,qBAAA,CA0Be,YAAA,EAAA,MAAA,CAAA,EA1B8B,UA0B9B;AAY/B;AAOA;AA0FA;AAyBgB,iBA7IA,cAAA,CAAA,CA6IQ,EAAA,MAAA;AAyBxB;;;iBA/JgB,eAAA,CAAA;;;;iBAYA,eAAA,CAAA;;;;iBAOA,yBAAA,CAAA,GAA6B;;;;;;;;iBA0F7B,aAAA,CAAA;;;;iBAyBA,QAAA,CAAA;;;;iBAyBA,iBAAA,CAAA"} | ||
| {"version":3,"file":"utils.d.ts","names":[],"sources":["../src/utils.ts"],"mappings":";;AAKA;;iBAAgB,qBAAA,CAAsB,YAAA,WAAuB,UAAA;;;AAmB7D;iBAAgB,cAAA,CAAA;;;;iBAOA,eAAA,CAAA;;;;iBAYA,eAAA,CAAA;AAAhB;;;AAAA,iBAOgB,yBAAA,CAAA,GAA6B,sBAAA;AA4I7C;;;AAAA,iBAlDgB,aAAA,CAAA;;;;iBAyBA,QAAA,CAAA;;;;iBAyBA,iBAAA,CAAA"} |
+1
-1
@@ -1,2 +0,2 @@ | ||
| import{NitroPingError as e}from"./types.js";function t(e){let t=`=`.repeat((4-e.length%4)%4),n=(e+t).replace(/-/g,`+`).replace(/_/g,`/`),r=globalThis.atob(n),i=new Uint8Array(r.length);for(let e=0;e<r.length;++e)i[e]=r.charCodeAt(e);return i}function n(){return`user-${Math.random().toString(36).substring(2,15)}-${Date.now()}`}function r(){return typeof globalThis<`u`&&`serviceWorker`in navigator&&`PushManager`in globalThis&&`Notification`in globalThis}function i(){return globalThis.isSecureContext===!0}function a(){return Notification.permission}async function o(t,n={}){let r=await fetch(t,{headers:{"Content-Type":`application/json`,...n.headers},...n});if(!r.ok){let t=await r.text(),n=`HTTP ${r.status}: ${r.statusText}`;try{let e=JSON.parse(t);n=e.message||n}catch{t&&(n=t)}throw new e(n,`API_ERROR`,r.status)}let i=r.headers.get(`content-type`);return i&&i.includes(`application/json`)?r.json():r.text()}function s(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch(e){console.warn(`Failed to save to localStorage:`,e)}}function c(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch(e){return console.warn(`Failed to read from localStorage:`,e),null}}function l(e){try{globalThis.localStorage.removeItem(e)}catch(e){console.warn(`Failed to remove from localStorage:`,e)}}function u(){let e=navigator.userAgent.toLowerCase();return e.includes(`chrome`)&&!e.includes(`edg`)?`chrome`:e.includes(`firefox`)?`firefox`:e.includes(`safari`)&&!e.includes(`chrome`)?`safari`:e.includes(`edg`)?`edge`:e.includes(`opera`)?`opera`:`unknown`}function d(){let e=navigator.userAgent.toLowerCase();return e.includes(`mac`)?`mac`:e.includes(`win`)?`windows`:e.includes(`linux`)?`linux`:e.includes(`android`)?`android`:e.includes(`iphone`)||e.includes(`ipad`)?`ios`:`unknown`}function f(){let e=navigator.userAgent,t=u();try{let n=null;switch(t){case`chrome`:n=e.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/);break;case`firefox`:n=e.match(/Firefox\/(\d+\.\d+)/);break;case`safari`:n=e.match(/Version\/(\d+\.\d+)/);break;case`edge`:n=e.match(/Edg\/(\d+\.\d+\.\d+\.\d+)/);break;case`opera`:n=e.match(/OPR\/(\d+\.\d+\.\d+\.\d+)/);break}return n?n[1]:`unknown`}catch{return`unknown`}}function p(e){switch(e.toLowerCase()){case`chrome`:return`CHROME`;case`firefox`:return`FIREFOX`;case`safari`:return`SAFARI`;case`edge`:return`EDGE`;case`opera`:return`OPERA`;default:return`WEB`}}export{o as apiRequest,u as detectBrowser,d as detectOS,n as generateUserId,f as getBrowserVersion,p as getCategoryFromBrowser,c as getLocalStorage,a as getNotificationPermission,r as isPushSupported,i as isSecureContext,l as removeLocalStorage,s as setLocalStorage,t as urlBase64ToUint8Array}; | ||
| import{NitroPingError as e}from"./types.js";function t(e){let t=(e+`=`.repeat((4-e.length%4)%4)).replace(/-/g,`+`).replace(/_/g,`/`),n=globalThis.atob(t),r=new Uint8Array(n.length);for(let e=0;e<n.length;++e)r[e]=n.charCodeAt(e);return r}function n(){return`user-${Math.random().toString(36).substring(2,15)}-${Date.now()}`}function r(){return typeof globalThis<`u`&&`serviceWorker`in navigator&&`PushManager`in globalThis&&`Notification`in globalThis}function i(){return globalThis.isSecureContext===!0}function a(){return Notification.permission}async function o(t,n={}){let r=await fetch(t,{headers:{"Content-Type":`application/json`,...n.headers},...n});if(!r.ok){let t=await r.text(),n=`HTTP ${r.status}: ${r.statusText}`;try{n=JSON.parse(t).message||n}catch{t&&(n=t)}throw new e(n,`API_ERROR`,r.status)}let i=r.headers.get(`content-type`);return i&&i.includes(`application/json`)?r.json():r.text()}function s(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch(e){console.warn(`Failed to save to localStorage:`,e)}}function c(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch(e){return console.warn(`Failed to read from localStorage:`,e),null}}function l(e){try{globalThis.localStorage.removeItem(e)}catch(e){console.warn(`Failed to remove from localStorage:`,e)}}function u(){let e=navigator.userAgent.toLowerCase();return e.includes(`chrome`)&&!e.includes(`edg`)?`chrome`:e.includes(`firefox`)?`firefox`:e.includes(`safari`)&&!e.includes(`chrome`)?`safari`:e.includes(`edg`)?`edge`:e.includes(`opera`)?`opera`:`unknown`}function d(){let e=navigator.userAgent.toLowerCase();return e.includes(`mac`)?`mac`:e.includes(`win`)?`windows`:e.includes(`linux`)?`linux`:e.includes(`android`)?`android`:e.includes(`iphone`)||e.includes(`ipad`)?`ios`:`unknown`}function f(){let e=navigator.userAgent,t=u();try{let n=null;switch(t){case`chrome`:n=e.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/);break;case`firefox`:n=e.match(/Firefox\/(\d+\.\d+)/);break;case`safari`:n=e.match(/Version\/(\d+\.\d+)/);break;case`edge`:n=e.match(/Edg\/(\d+\.\d+\.\d+\.\d+)/);break;case`opera`:n=e.match(/OPR\/(\d+\.\d+\.\d+\.\d+)/);break}return n?n[1]:`unknown`}catch{return`unknown`}}function p(e){switch(e.toLowerCase()){case`chrome`:return`CHROME`;case`firefox`:return`FIREFOX`;case`safari`:return`SAFARI`;case`edge`:return`EDGE`;case`opera`:return`OPERA`;default:return`WEB`}}export{o as apiRequest,u as detectBrowser,d as detectOS,n as generateUserId,f as getBrowserVersion,p as getCategoryFromBrowser,c as getLocalStorage,a as getNotificationPermission,r as isPushSupported,i as isSecureContext,l as removeLocalStorage,s as setLocalStorage,t as urlBase64ToUint8Array}; | ||
| //# sourceMappingURL=utils.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"utils.js","names":["match: RegExpMatchArray | null"],"sources":["../src/utils.ts"],"sourcesContent":["import { NitroPingError } from './types.ts'\n\n/**\n * Converts a VAPID public key from base64url format to Uint8Array for use with the Push API\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - base64String.length % 4) % 4)\n const base64 = (base64String + padding)\n .replace(/-/g, '+')\n .replace(/_/g, '/')\n\n const rawData = globalThis.atob(base64)\n const outputArray = new Uint8Array(rawData.length)\n\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i)\n }\n\n return outputArray\n}\n\n/**\n * Generates a random user ID for anonymous users\n */\nexport function generateUserId(): string {\n return `user-${Math.random().toString(36).substring(2, 15)}-${Date.now()}`\n}\n\n/**\n * Checks if the current environment supports push notifications\n */\nexport function isPushSupported(): boolean {\n return (\n typeof globalThis !== 'undefined'\n && 'serviceWorker' in navigator\n && 'PushManager' in globalThis\n && 'Notification' in globalThis\n )\n}\n\n/**\n * Checks if we're running in a secure context (required for push notifications)\n */\nexport function isSecureContext(): boolean {\n return globalThis.isSecureContext === true\n}\n\n/**\n * Gets the current notification permission status\n */\nexport function getNotificationPermission(): NotificationPermission {\n return Notification.permission\n}\n\n/**\n * Makes an HTTP request to the NitroPing API\n */\nexport async function apiRequest<T = any>(\n url: string,\n options: RequestInit = {},\n): Promise<T> {\n const response = await fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n ...options,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\n try {\n const errorData = JSON.parse(errorText)\n errorMessage = errorData.message || errorMessage\n }\n catch {\n // If it's not JSON, use the raw text\n if (errorText) {\n errorMessage = errorText\n }\n }\n\n throw new NitroPingError(\n errorMessage,\n 'API_ERROR',\n response.status,\n )\n }\n\n const contentType = response.headers.get('content-type')\n if (contentType && contentType.includes('application/json')) {\n return response.json()\n }\n\n return response.text() as T\n}\n\n/**\n * Stores data in localStorage with error handling\n */\nexport function setLocalStorage(key: string, value: any): void {\n try {\n globalThis.localStorage.setItem(key, JSON.stringify(value))\n }\n catch (error) {\n console.warn('Failed to save to localStorage:', error)\n }\n}\n\n/**\n * Retrieves data from localStorage with error handling\n */\nexport function getLocalStorage<T = any>(key: string): T | null {\n try {\n const item = globalThis.localStorage.getItem(key)\n return item ? JSON.parse(item) : null\n }\n catch (error) {\n console.warn('Failed to read from localStorage:', error)\n return null\n }\n}\n\n/**\n * Removes data from localStorage\n */\nexport function removeLocalStorage(key: string): void {\n try {\n globalThis.localStorage.removeItem(key)\n }\n catch (error) {\n console.warn('Failed to remove from localStorage:', error)\n }\n}\n\n/**\n * Detects the browser type from user agent\n */\nexport function detectBrowser(): string {\n const userAgent = navigator.userAgent.toLowerCase()\n\n if (userAgent.includes('chrome') && !userAgent.includes('edg')) {\n return 'chrome'\n }\n if (userAgent.includes('firefox')) {\n return 'firefox'\n }\n if (userAgent.includes('safari') && !userAgent.includes('chrome')) {\n return 'safari'\n }\n if (userAgent.includes('edg')) {\n return 'edge'\n }\n if (userAgent.includes('opera')) {\n return 'opera'\n }\n\n return 'unknown'\n}\n\n/**\n * Detects the operating system from user agent\n */\nexport function detectOS(): string {\n const userAgent = navigator.userAgent.toLowerCase()\n\n if (userAgent.includes('mac')) {\n return 'mac'\n }\n if (userAgent.includes('win')) {\n return 'windows'\n }\n if (userAgent.includes('linux')) {\n return 'linux'\n }\n if (userAgent.includes('android')) {\n return 'android'\n }\n if (userAgent.includes('iphone') || userAgent.includes('ipad')) {\n return 'ios'\n }\n\n return 'unknown'\n}\n\n/**\n * Gets browser version from user agent\n */\nexport function getBrowserVersion(): string {\n const userAgent = navigator.userAgent\n const browser = detectBrowser()\n\n try {\n let match: RegExpMatchArray | null = null\n\n switch (browser) {\n case 'chrome':\n match = userAgent.match(/Chrome\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n case 'firefox':\n match = userAgent.match(/Firefox\\/(\\d+\\.\\d+)/)\n break\n case 'safari':\n match = userAgent.match(/Version\\/(\\d+\\.\\d+)/)\n break\n case 'edge':\n match = userAgent.match(/Edg\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n case 'opera':\n match = userAgent.match(/OPR\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n }\n\n return match ? match[1] : 'unknown'\n }\n catch {\n return 'unknown'\n }\n}\n\n/**\n * Maps browser type to category enum value (only for supported browsers)\n */\nexport function getCategoryFromBrowser(browser: string): string {\n switch (browser.toLowerCase()) {\n case 'chrome':\n return 'CHROME'\n case 'firefox':\n return 'FIREFOX'\n case 'safari':\n return 'SAFARI'\n case 'edge':\n return 'EDGE'\n case 'opera':\n return 'OPERA'\n default:\n return 'WEB' // Will be filtered out in SDK\n }\n}\n"],"mappings":"4CAKA,SAAgB,EAAsB,EAAkC,CACtE,IAAM,EAAU,IAAI,QAAQ,EAAI,EAAa,OAAS,GAAK,GACrD,GAAU,EAAe,GAC5B,QAAQ,KAAM,KACd,QAAQ,KAAM,KAEX,EAAU,WAAW,KAAK,GAC1B,EAAc,IAAI,WAAW,EAAQ,QAE3C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,EAAE,EACpC,EAAY,GAAK,EAAQ,WAAW,GAGtC,OAAO,CACR,CAKD,SAAgB,GAAyB,CACvC,MAAO,QAAQ,KAAK,SAAS,SAAS,IAAI,UAAU,EAAG,IAAI,GAAG,KAAK,OACpE,CAKD,SAAgB,GAA2B,CACzC,OACE,OAAO,WAAe,KACnB,kBAAmB,WACnB,gBAAiB,YACjB,iBAAkB,UAExB,CAKD,SAAgB,GAA2B,CACzC,OAAO,WAAW,kBAAoB,EACvC,CAKD,SAAgB,GAAoD,CAClE,OAAO,aAAa,UACrB,CAKD,eAAsB,EACpB,EACA,EAAuB,EAAE,CACb,CACZ,IAAM,EAAW,MAAM,MAAM,EAAK,CAChC,QAAS,CACP,eAAgB,mBAChB,GAAG,EAAQ,QACZ,CACD,GAAG,EACJ,EAED,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAY,MAAM,EAAS,OAC7B,EAAe,QAAQ,EAAS,OAAO,IAAI,EAAS,aAExD,GAAI,CACF,IAAM,EAAY,KAAK,MAAM,GAC7B,EAAe,EAAU,SAAW,CACrC,MACK,CAEA,IACF,EAAe,EAElB,CAED,MAAM,IAAI,EACR,EACA,YACA,EAAS,OAEZ,CAED,IAAM,EAAc,EAAS,QAAQ,IAAI,gBAKzC,OAJI,GAAe,EAAY,SAAS,oBAC/B,EAAS,OAGX,EAAS,MACjB,CAKD,SAAgB,EAAgB,EAAa,EAAkB,CAC7D,GAAI,CACF,WAAW,aAAa,QAAQ,EAAK,KAAK,UAAU,GACrD,OACM,EAAO,CACZ,QAAQ,KAAK,kCAAmC,EACjD,CACF,CAKD,SAAgB,EAAyB,EAAuB,CAC9D,GAAI,CACF,IAAM,EAAO,WAAW,aAAa,QAAQ,GAC7C,OAAO,EAAO,KAAK,MAAM,GAAQ,IAClC,OACM,EAAO,CAEZ,OADA,QAAQ,KAAK,oCAAqC,GAC3C,IACR,CACF,CAKD,SAAgB,EAAmB,EAAmB,CACpD,GAAI,CACF,WAAW,aAAa,WAAW,EACpC,OACM,EAAO,CACZ,QAAQ,KAAK,sCAAuC,EACrD,CACF,CAKD,SAAgB,GAAwB,CACtC,IAAM,EAAY,UAAU,UAAU,cAkBtC,OAhBI,EAAU,SAAS,WAAa,CAAC,EAAU,SAAS,OAC/C,SAEL,EAAU,SAAS,WACd,UAEL,EAAU,SAAS,WAAa,CAAC,EAAU,SAAS,UAC/C,SAEL,EAAU,SAAS,OACd,OAEL,EAAU,SAAS,SACd,QAGF,SACR,CAKD,SAAgB,GAAmB,CACjC,IAAM,EAAY,UAAU,UAAU,cAkBtC,OAhBI,EAAU,SAAS,OACd,MAEL,EAAU,SAAS,OACd,UAEL,EAAU,SAAS,SACd,QAEL,EAAU,SAAS,WACd,UAEL,EAAU,SAAS,WAAa,EAAU,SAAS,QAC9C,MAGF,SACR,CAKD,SAAgB,GAA4B,CAC1C,IAAM,EAAY,UAAU,UACtB,EAAU,IAEhB,GAAI,CACF,IAAIA,EAAiC,KAErC,OAAQ,EAAR,CACE,IAAK,SACH,EAAQ,EAAU,MAAM,gCACxB,MACF,IAAK,UACH,EAAQ,EAAU,MAAM,uBACxB,MACF,IAAK,SACH,EAAQ,EAAU,MAAM,uBACxB,MACF,IAAK,OACH,EAAQ,EAAU,MAAM,6BACxB,MACF,IAAK,QACH,EAAQ,EAAU,MAAM,6BACxB,KACH,CAED,OAAO,EAAQ,EAAM,GAAK,SAC3B,MACK,CACJ,MAAO,SACR,CACF,CAKD,SAAgB,EAAuB,EAAyB,CAC9D,OAAQ,EAAQ,cAAhB,CACE,IAAK,SACH,MAAO,SACT,IAAK,UACH,MAAO,UACT,IAAK,SACH,MAAO,SACT,IAAK,OACH,MAAO,OACT,IAAK,QACH,MAAO,QACT,QACE,MAAO,KACV,CACF"} | ||
| {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { NitroPingError } from './types.ts'\n\n/**\n * Converts a VAPID public key from base64url format to Uint8Array for use with the Push API\n */\nexport function urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - base64String.length % 4) % 4)\n const base64 = (base64String + padding)\n .replace(/-/g, '+')\n .replace(/_/g, '/')\n\n const rawData = globalThis.atob(base64)\n const outputArray = new Uint8Array(rawData.length)\n\n for (let i = 0; i < rawData.length; ++i) {\n outputArray[i] = rawData.charCodeAt(i)\n }\n\n return outputArray\n}\n\n/**\n * Generates a random user ID for anonymous users\n */\nexport function generateUserId(): string {\n return `user-${Math.random().toString(36).substring(2, 15)}-${Date.now()}`\n}\n\n/**\n * Checks if the current environment supports push notifications\n */\nexport function isPushSupported(): boolean {\n return (\n typeof globalThis !== 'undefined'\n && 'serviceWorker' in navigator\n && 'PushManager' in globalThis\n && 'Notification' in globalThis\n )\n}\n\n/**\n * Checks if we're running in a secure context (required for push notifications)\n */\nexport function isSecureContext(): boolean {\n return globalThis.isSecureContext === true\n}\n\n/**\n * Gets the current notification permission status\n */\nexport function getNotificationPermission(): NotificationPermission {\n return Notification.permission\n}\n\n/**\n * Makes an HTTP request to the NitroPing API\n */\nexport async function apiRequest<T = any>(\n url: string,\n options: RequestInit = {},\n): Promise<T> {\n const response = await fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n ...options,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\n try {\n const errorData = JSON.parse(errorText)\n errorMessage = errorData.message || errorMessage\n }\n catch {\n // If it's not JSON, use the raw text\n if (errorText) {\n errorMessage = errorText\n }\n }\n\n throw new NitroPingError(\n errorMessage,\n 'API_ERROR',\n response.status,\n )\n }\n\n const contentType = response.headers.get('content-type')\n if (contentType && contentType.includes('application/json')) {\n return response.json()\n }\n\n return response.text() as T\n}\n\n/**\n * Stores data in localStorage with error handling\n */\nexport function setLocalStorage(key: string, value: any): void {\n try {\n globalThis.localStorage.setItem(key, JSON.stringify(value))\n }\n catch (error) {\n console.warn('Failed to save to localStorage:', error)\n }\n}\n\n/**\n * Retrieves data from localStorage with error handling\n */\nexport function getLocalStorage<T = any>(key: string): T | null {\n try {\n const item = globalThis.localStorage.getItem(key)\n return item ? JSON.parse(item) : null\n }\n catch (error) {\n console.warn('Failed to read from localStorage:', error)\n return null\n }\n}\n\n/**\n * Removes data from localStorage\n */\nexport function removeLocalStorage(key: string): void {\n try {\n globalThis.localStorage.removeItem(key)\n }\n catch (error) {\n console.warn('Failed to remove from localStorage:', error)\n }\n}\n\n/**\n * Detects the browser type from user agent\n */\nexport function detectBrowser(): string {\n const userAgent = navigator.userAgent.toLowerCase()\n\n if (userAgent.includes('chrome') && !userAgent.includes('edg')) {\n return 'chrome'\n }\n if (userAgent.includes('firefox')) {\n return 'firefox'\n }\n if (userAgent.includes('safari') && !userAgent.includes('chrome')) {\n return 'safari'\n }\n if (userAgent.includes('edg')) {\n return 'edge'\n }\n if (userAgent.includes('opera')) {\n return 'opera'\n }\n\n return 'unknown'\n}\n\n/**\n * Detects the operating system from user agent\n */\nexport function detectOS(): string {\n const userAgent = navigator.userAgent.toLowerCase()\n\n if (userAgent.includes('mac')) {\n return 'mac'\n }\n if (userAgent.includes('win')) {\n return 'windows'\n }\n if (userAgent.includes('linux')) {\n return 'linux'\n }\n if (userAgent.includes('android')) {\n return 'android'\n }\n if (userAgent.includes('iphone') || userAgent.includes('ipad')) {\n return 'ios'\n }\n\n return 'unknown'\n}\n\n/**\n * Gets browser version from user agent\n */\nexport function getBrowserVersion(): string {\n const userAgent = navigator.userAgent\n const browser = detectBrowser()\n\n try {\n let match: RegExpMatchArray | null = null\n\n switch (browser) {\n case 'chrome':\n match = userAgent.match(/Chrome\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n case 'firefox':\n match = userAgent.match(/Firefox\\/(\\d+\\.\\d+)/)\n break\n case 'safari':\n match = userAgent.match(/Version\\/(\\d+\\.\\d+)/)\n break\n case 'edge':\n match = userAgent.match(/Edg\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n case 'opera':\n match = userAgent.match(/OPR\\/(\\d+\\.\\d+\\.\\d+\\.\\d+)/)\n break\n }\n\n return match ? match[1] : 'unknown'\n }\n catch {\n return 'unknown'\n }\n}\n\n/**\n * Maps browser type to category enum value (only for supported browsers)\n */\nexport function getCategoryFromBrowser(browser: string): string {\n switch (browser.toLowerCase()) {\n case 'chrome':\n return 'CHROME'\n case 'firefox':\n return 'FIREFOX'\n case 'safari':\n return 'SAFARI'\n case 'edge':\n return 'EDGE'\n case 'opera':\n return 'OPERA'\n default:\n return 'WEB' // Will be filtered out in SDK\n }\n}\n"],"mappings":"4CAKA,SAAgB,EAAsB,EAAkC,CAEtE,IAAM,GAAU,EADA,IAAI,QAAQ,EAAI,EAAa,OAAS,GAAK,EAAE,EAE1D,QAAQ,KAAM,IAAI,CAClB,QAAQ,KAAM,IAAI,CAEf,EAAU,WAAW,KAAK,EAAO,CACjC,EAAc,IAAI,WAAW,EAAQ,OAAO,CAElD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,EAAE,EACpC,EAAY,GAAK,EAAQ,WAAW,EAAE,CAGxC,OAAO,EAMT,SAAgB,GAAyB,CACvC,MAAO,QAAQ,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,UAAU,EAAG,GAAG,CAAC,GAAG,KAAK,KAAK,GAM1E,SAAgB,GAA2B,CACzC,OACE,OAAO,WAAe,KACnB,kBAAmB,WACnB,gBAAiB,YACjB,iBAAkB,WAOzB,SAAgB,GAA2B,CACzC,OAAO,WAAW,kBAAoB,GAMxC,SAAgB,GAAoD,CAClE,OAAO,aAAa,WAMtB,eAAsB,EACpB,EACA,EAAuB,EAAE,CACb,CACZ,IAAM,EAAW,MAAM,MAAM,EAAK,CAChC,QAAS,CACP,eAAgB,mBAChB,GAAG,EAAQ,QACZ,CACD,GAAG,EACJ,CAAC,CAEF,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAY,MAAM,EAAS,MAAM,CACnC,EAAe,QAAQ,EAAS,OAAO,IAAI,EAAS,aAExD,GAAI,CAEF,EADkB,KAAK,MAAM,EAAU,CACd,SAAW,OAEhC,CAEA,IACF,EAAe,GAInB,MAAM,IAAI,EACR,EACA,YACA,EAAS,OACV,CAGH,IAAM,EAAc,EAAS,QAAQ,IAAI,eAAe,CAKxD,OAJI,GAAe,EAAY,SAAS,mBAAmB,CAClD,EAAS,MAAM,CAGjB,EAAS,MAAM,CAMxB,SAAgB,EAAgB,EAAa,EAAkB,CAC7D,GAAI,CACF,WAAW,aAAa,QAAQ,EAAK,KAAK,UAAU,EAAM,CAAC,OAEtD,EAAO,CACZ,QAAQ,KAAK,kCAAmC,EAAM,EAO1D,SAAgB,EAAyB,EAAuB,CAC9D,GAAI,CACF,IAAM,EAAO,WAAW,aAAa,QAAQ,EAAI,CACjD,OAAO,EAAO,KAAK,MAAM,EAAK,CAAG,WAE5B,EAAO,CAEZ,OADA,QAAQ,KAAK,oCAAqC,EAAM,CACjD,MAOX,SAAgB,EAAmB,EAAmB,CACpD,GAAI,CACF,WAAW,aAAa,WAAW,EAAI,OAElC,EAAO,CACZ,QAAQ,KAAK,sCAAuC,EAAM,EAO9D,SAAgB,GAAwB,CACtC,IAAM,EAAY,UAAU,UAAU,aAAa,CAkBnD,OAhBI,EAAU,SAAS,SAAS,EAAI,CAAC,EAAU,SAAS,MAAM,CACrD,SAEL,EAAU,SAAS,UAAU,CACxB,UAEL,EAAU,SAAS,SAAS,EAAI,CAAC,EAAU,SAAS,SAAS,CACxD,SAEL,EAAU,SAAS,MAAM,CACpB,OAEL,EAAU,SAAS,QAAQ,CACtB,QAGF,UAMT,SAAgB,GAAmB,CACjC,IAAM,EAAY,UAAU,UAAU,aAAa,CAkBnD,OAhBI,EAAU,SAAS,MAAM,CACpB,MAEL,EAAU,SAAS,MAAM,CACpB,UAEL,EAAU,SAAS,QAAQ,CACtB,QAEL,EAAU,SAAS,UAAU,CACxB,UAEL,EAAU,SAAS,SAAS,EAAI,EAAU,SAAS,OAAO,CACrD,MAGF,UAMT,SAAgB,GAA4B,CAC1C,IAAM,EAAY,UAAU,UACtB,EAAU,GAAe,CAE/B,GAAI,CACF,IAAI,EAAiC,KAErC,OAAQ,EAAR,CACE,IAAK,SACH,EAAQ,EAAU,MAAM,+BAA+B,CACvD,MACF,IAAK,UACH,EAAQ,EAAU,MAAM,sBAAsB,CAC9C,MACF,IAAK,SACH,EAAQ,EAAU,MAAM,sBAAsB,CAC9C,MACF,IAAK,OACH,EAAQ,EAAU,MAAM,4BAA4B,CACpD,MACF,IAAK,QACH,EAAQ,EAAU,MAAM,4BAA4B,CACpD,MAGJ,OAAO,EAAQ,EAAM,GAAK,eAEtB,CACJ,MAAO,WAOX,SAAgB,EAAuB,EAAyB,CAC9D,OAAQ,EAAQ,aAAa,CAA7B,CACE,IAAK,SACH,MAAO,SACT,IAAK,UACH,MAAO,UACT,IAAK,SACH,MAAO,SACT,IAAK,OACH,MAAO,OACT,IAAK,QACH,MAAO,QACT,QACE,MAAO"} |
+10
-11
| { | ||
| "name": "nitroping", | ||
| "type": "module", | ||
| "version": "0.1.0", | ||
| "version": "0.2.0", | ||
| "description": "JavaScript/TypeScript SDK for NitroPing push notification service", | ||
@@ -26,4 +26,2 @@ "author": "NitroPing Team", | ||
| }, | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
@@ -34,16 +32,17 @@ "files": [ | ||
| "engines": { | ||
| "node": ">=22" | ||
| "node": ">=24" | ||
| }, | ||
| "peerDependencies": {}, | ||
| "devDependencies": { | ||
| "tsdown": "^0.14.1", | ||
| "typescript": "^5.9.2" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsdown", | ||
| "dev": "tsdown --watch", | ||
| "postinstall": "tsdown", | ||
| "typecheck": "tsc --noEmit", | ||
| "clean": "rm -rf dist", | ||
| "release": "pnpm build && pnpm publish --no-git-checks --access public" | ||
| "release": "bun run build && bun publish --no-git-checks --access public" | ||
| }, | ||
| "peerDependencies": {}, | ||
| "devDependencies": { | ||
| "tsdown": "^0.20.3", | ||
| "typescript": "^5.9.3" | ||
| } | ||
| } | ||
| } |
| import{toPropertyKey as e}from"./toPropertyKey.js";function t(t,n,r){return(n=e(n))in t?Object.defineProperty(t,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[n]=r,t}export{t as _defineProperty}; | ||
| //# sourceMappingURL=defineProperty.js.map |
| {"version":3,"file":"defineProperty.js","names":[],"sources":["../../../../../../../../../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/esm/defineProperty.js"],"sourcesContent":["import toPropertyKey from \"./toPropertyKey.js\";\nfunction _defineProperty(e, r, t) {\n return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n value: t,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }) : e[r] = t, e;\n}\nexport { _defineProperty as default };"],"x_google_ignoreList":[0],"mappings":"mDACA,SAAS,EAAgB,EAAG,EAAG,EAAG,CAChC,OAAQ,EAAI,EAAc,MAAO,EAAI,OAAO,eAAe,EAAG,EAAG,CAC/D,MAAO,EACP,WAAY,CAAC,EACb,aAAc,CAAC,EACf,SAAU,CAAC,EACZ,EAAI,EAAE,GAAK,EAAG,CAChB"} |
| import{_typeof as e}from"./typeof.js";function t(t,n){if(e(t)!=`object`||!t)return t;var r=t[Symbol.toPrimitive];if(r!==void 0){var i=r.call(t,n||`default`);if(e(i)!=`object`)return i;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(n===`string`?String:Number)(t)}export{t as toPrimitive}; | ||
| //# sourceMappingURL=toPrimitive.js.map |
| {"version":3,"file":"toPrimitive.js","names":[],"sources":["../../../../../../../../../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/esm/toPrimitive.js"],"sourcesContent":["import _typeof from \"./typeof.js\";\nfunction toPrimitive(t, r) {\n if (\"object\" != _typeof(t) || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != _typeof(i)) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nexport { toPrimitive as default };"],"x_google_ignoreList":[0],"mappings":"sCACA,SAAS,EAAY,EAAG,EAAG,CACzB,GAAgB,EAAQ,IAApB,UAA0B,CAAC,EAAG,OAAO,EACzC,IAAI,EAAI,EAAE,OAAO,aACjB,GAAe,IAAX,IAAK,GAAS,CAChB,IAAI,EAAI,EAAE,KAAK,EAAG,GAAK,WACvB,GAAgB,EAAQ,IAApB,SAAwB,OAAO,EACnC,MAAU,UAAU,+CACrB,CACD,OAAqB,IAAb,SAAiB,OAAS,QAAQ,EAC3C"} |
| import{_typeof as e}from"./typeof.js";import{toPrimitive as t}from"./toPrimitive.js";function n(n){var r=t(n,`string`);return e(r)==`symbol`?r:r+``}export{n as toPropertyKey}; | ||
| //# sourceMappingURL=toPropertyKey.js.map |
| {"version":3,"file":"toPropertyKey.js","names":[],"sources":["../../../../../../../../../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/esm/toPropertyKey.js"],"sourcesContent":["import _typeof from \"./typeof.js\";\nimport toPrimitive from \"./toPrimitive.js\";\nfunction toPropertyKey(t) {\n var i = toPrimitive(t, \"string\");\n return \"symbol\" == _typeof(i) ? i : i + \"\";\n}\nexport { toPropertyKey as default };"],"x_google_ignoreList":[0],"mappings":"qFAEA,SAAS,EAAc,EAAG,CACxB,IAAI,EAAI,EAAY,EAAG,UACvB,OAAmB,EAAQ,IAApB,SAAyB,EAAI,EAAI,EACzC"} |
| function e(t){"@babel/helpers - typeof";return e=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},e(t)}export{e as _typeof}; | ||
| //# sourceMappingURL=typeof.js.map |
| {"version":3,"file":"typeof.js","names":["o"],"sources":["../../../../../../../../../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/esm/typeof.js"],"sourcesContent":["function _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}\nexport { _typeof as default };"],"x_google_ignoreList":[0],"mappings":"AAAA,SAAS,EAAQ,EAAG,CAClB,0BAEA,MAAO,GAAwB,OAAO,QAArB,YAA2C,OAAO,OAAO,UAA1B,SAAqC,SAAU,EAAG,CAChG,OAAO,OAAOA,CACf,EAAG,SAAU,EAAG,CACf,OAAOA,GAAmB,OAAO,QAArB,YAA+BA,EAAE,cAAgB,QAAUA,IAAM,OAAO,UAAY,SAAW,OAAOA,CACnH,EAAE,EAAQ,EACZ"} |
Install scripts
Supply chain riskInstall scripts are run when the package is installed or built. Malicious packages often use scripts that run automatically to execute payloads or fetch additional code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Known malware
Supply chain riskThis package version is identified as malware. It has been flagged either by Socket's AI scanner and confirmed by our threat research team, or is listed as malicious in security databases and other sources.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances in 1 package
53222
25.53%341
58.6%4
-42.86%0
-100%1
-50%16
-33.33%1
Infinity%1
Infinity%