diff --git a/.eslintrc.js b/.eslintrc.js index 7fd87f1..a731c54 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,6 @@ module.exports = { extensions: [ ".js", ".ts", - ".tsx", ], }, }, @@ -28,6 +27,9 @@ module.exports = { plugins: [ '@typescript-eslint', ], + extends: [ + 'plugin:@typescript-eslint/recommended', + ], rules: { "prefer-destructuring": 0, "no-param-reassign": 0, @@ -35,6 +37,7 @@ module.exports = { "dot-notation": 0, "no-continue": 0, "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error"] + "@typescript-eslint/no-unused-vars": ["error"], + "no-prototype-builtins": "warn", }, }; diff --git a/.github/ISSUE_TEMPLATE/ask-question.yml b/.github/ISSUE_TEMPLATE/ask-question.yml index 42c6589..34ec8b4 100644 --- a/.github/ISSUE_TEMPLATE/ask-question.yml +++ b/.github/ISSUE_TEMPLATE/ask-question.yml @@ -1,6 +1,6 @@ name: πŸ™‹β€β™‚οΈ Ask a question description: Tell us what's on your mind -title: "[question]: " +title: "[Question]: " labels: ["triage"] assignees: - OneSignal/eng-developer-sdk diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index b5c9f32..7d71916 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -17,6 +17,29 @@ body: placeholder: The latest version of the SDK causes a runtime error. validations: required: true + - type: dropdown + id: browsers + attributes: + label: What browsers are you seeing the problem on? + multiple: true + options: + - Firefox + - Chrome (Chromium) + - Safari + - Microsoft Edge + - Opera + - Brave + - Other + validations: + required: true + - type: input + id: operating-system + attributes: + label: What operating system are you running? + description: Make sure to include the version. + placeholder: macOS Monterey 12.3.1 + validations: + required: true - type: textarea id: reproduction-steps attributes: @@ -44,3 +67,4 @@ body: label: Relevant log output description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. render: Shell + diff --git a/.github/ISSUE_TEMPLATE/general-feedback.yml b/.github/ISSUE_TEMPLATE/general-feedback.yml index 5e679ed..185127d 100644 --- a/.github/ISSUE_TEMPLATE/general-feedback.yml +++ b/.github/ISSUE_TEMPLATE/general-feedback.yml @@ -1,6 +1,6 @@ name: πŸ“£ General feedback description: Tell us what's on your mind -title: "[Bug]: " +title: "[Feedback]: " labels: ["triage"] assignees: - OneSignal/eng-developer-sdk diff --git a/.github/ISSUE_TEMPLATE/workflows/Zapier.yml b/.github/ISSUE_TEMPLATE/workflows/Zapier.yml new file mode 100644 index 0000000..3665dd5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/workflows/Zapier.yml @@ -0,0 +1,34 @@ +# This is an action to close asana tasks that were generated by Github issues + +name: Zapier web hook + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + issues: + types: [closed] + +permissions: + issues: read + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Runs a set of commands using the runners shell + - name: Call Zapier web hook to close Asana task + if: ${{ !github.event.issue.pull_request }} + env: + ISSUE_TITLE: ${{ github.event.issue.title }} + run: | + curl --location --request POST 'https://hooks.zapier.com/hooks/catch/12728683/b7009qc/' \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --data-raw '{ + "task_name" : "$ISSUE_TITLE" + }' diff --git a/.github/ISSUE_TEMPLATE/workflows/release-drafter.yml b/.github/ISSUE_TEMPLATE/workflows/release-drafter.yml new file mode 100644 index 0000000..82e66d2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/workflows/release-drafter.yml @@ -0,0 +1,41 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - main + # pull_request event is required only for autolabeler + pull_request: + # Only following types are handled by the action, but one can default to all as well + types: [opened, reopened, synchronize] + # pull_request_target event is required for autolabeler to support PRs from forks + # pull_request_target: + # types: [opened, reopened, synchronize] + +permissions: + contents: read + +jobs: + update_release_draft: + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + runs-on: ubuntu-latest + steps: + # (Optional) GitHub Enterprise requires GHE_HOST variable set + #- name: Set GHE_HOST + # run: | + # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV + + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml + # with: + # config-name: my-config.yml + # disable-autolabeler: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/MigrationGuide.md b/MigrationGuide.md new file mode 100644 index 0000000..e4b8e6c --- /dev/null +++ b/MigrationGuide.md @@ -0,0 +1,251 @@ + +# Migration Guide + +## Version 2 +### Intro +In this release, we are making a significant shift from a device-centered model to a user-centered model. This means that instead of identifying devices, we now focus on identifying individual users. This update is part of a larger effort to shift towards a user-oriented omni-channel messaging system. + +To facilitate this change, the externalId approach for identifying users is being replaced by the login and logout methods. In addition, the SDK now makes use of namespaces such as User, Notifications, and Slidedown to better separate code. + +This guide will walk you through these and other important changes in the version 16 update. + +### Overview +Under the new model, the concept of a "player" is being updated to include three new concepts: users, subscriptions, and aliases. + +### Users +Users own subscriptions and are identified by aliases which are used to point to users using different alias schemes. + +### Subscriptions + +Subscriptions refer to the way in which a user can receive various communication methods offered by OneSignal, including push notifications, SMS, and email. + +### Aliases +Aliases are identifiers that point to users and are made up of an alias label and id. Users can have multiple aliases. Consider the need to identify a user with your own application's unique identifier as well as identifiers from other integrated applications. + +The SDK will use `external_id` as the default alias label for the public `OneSignal.login("1234")` method. + +**Alias Example:** +``` +"aliases": [ + { + "label": "external_id", + "id": "1234" + }, + { + "label": "my_alias", + "id": "5678" + } +] +``` + +```js +// WebSDK-specific example +{ + external_id: "1234", + my_alias: "5678" +} +``` + +# Guide +## 1. Setup Changes +### Service Worker File + +From: +```js +importScripts("https://onesignal.com/sdks/OneSignalSDKWorker.js"); +``` + +To: +```js +importScripts("https://onesignal.com/sdks/web/v16/OneSignalSDK.sw.js"); +``` + +## 2. External User ID +Update any usages of `OneSignal.setExternalId` to `OneSignal.login` or `OneSignal.logout` +From: +```js +OneSignal.setExternalId("myId"); +``` + +To: +```js +OneSignal.login("myId"); +``` + +Use `OneSignal.logout();` instead anywhere you have `OneSignal.setExternalId("");` or are setting it to `null`. + +## 3. API Changes +Update your code to use the new API. The following namespaces are on the `OneSignal` object. + +### User Namespace + +Example: +```js +OneSignal.User.addAlias("my_alias", "1234"); +``` + +All user functions are synchronous. + +| Function Name | Description | Argument List | +| --------------- | ---------------------------------------------- | ------------------------------------ | +| `addAlias` | Adds a new alias for the current user. | `label: string, id: string` | +| `addAliases` | Adds multiple aliases for the current user. | `aliases: { [key: string]: string }` | +| `removeAlias` | Removes an alias for the current user. | `label: string` | +| `removeAliases` | Removes multiple aliases for the current user. | `labels: string[]` | +| `addEmail` | Adds an email address for the current user. | `email: string` | +| `removeEmail` | Removes an email address for the current user. | `email: string` | +| `addSms` | Adds an SMS number for the current user. | `smsNumber: string` | +| `removeSms` | Removes an SMS number for the current user. | `smsNumber: string` | +| `addTag` | Adds a tag for the current user. | `key: string, value: string` | +| `addTags` | Adds multiple tags for the current user. | `tags: { [key: string]: string }` | +| `removeTag` | Removes a tag for the current user. | `key: string` | +| `removeTags` | Removes multiple tags for the current user. | `keys: string[]` | + +### Notifications Namespace + +Example: +```js +await OneSignal.Notifications.requestPermission(); +``` + +| Sync/Async | Function Name | Description | Argument List | +| ---------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `async` | `setDefaultUrl` | Sets the default URL for notifications. | `url` (string) | +| `async` | `setDefaultTitle` | Sets the default title for notifications. | `title` (string) | +| `sync` | `isPushSupported` | Returns true if the current browser supports web push. | | +| `async` | `getPermissionStatus` | Returns the browser's current notification permission. | `onComplete` (Action) | +| `async` | `requestPermission` | Requests push notifications permission via the native browser prompt. | | +| `sync` | `addEventListener` | Adds an event listener for the following events:

- `click`
- `willDisplay`
- `dismiss`
- `permissionPromptDisplay`
- `permissionChange`*
* argument type: bool | - `` (string)
- `(arg: ) => {}` (callback) | +| `sync` | `removeEventListener` | Removes the event listener. | `() => {}` (the event listener you want to remove) | + + + +### Slidedown Namespace + +Example: +```js +await OneSignal.Slidedown.promptPush(); +``` + +| Sync/Async | Function Name | Description | Argument List | +| ---------- | ---------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | +| `async` | `promptPush` | Displays the notification permission prompt. | `options` (AutoPromptOptions) | +| `async` | `promptPushCategories` | Displays the notification permission prompt for notification categories. | `options` (AutoPromptOptions) | +| `async` | `promptSms` | Displays the SMS subscription prompt. | `options` (AutoPromptOptions) | +| `async` | `promptEmail` | Displays the email subscription prompt. | `options` (AutoPromptOptions) | +| `async` | `promptSmsAndEmail` | Displays the SMS and email subscription prompts. | `options` (AutoPromptOptions) | +| `sync` | `addEventListener` | Adds an event listener for the `slidedownShown` event. | - `event` ("slidedownShown"),
- `listener` ((wasShown: boolean) => void) | +| `sync` | `removeEventListener` | Removes an event listener for the `slidedownShown` event. | - `event` ("slidedownShown")
- `listener` ((wasShown: boolean) => void) | + + + +### Push Subscription Namespace + +Example: +```js +OneSignal.User.PushSubscription.optIn(); +``` + +| Sync/Async | Property/Function | Description | Argument List | +| ---------- | ----------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| | `id` | Gets the current user's ID. | | +| | `token` | Gets the current user's push notification token. | | +| | `optedIn` | Gets a boolean value indicating whether the current user is subscribed to push notifications. | | +| `async` | `optIn()` | Subscribes the current user to push notifications. | | +| `async` | `optOut()` | Unsubscribes the current user from push notifications. | | +| `sync` | `addEventListener()` | Adds an event listener for the `subscriptionChange` event. | - `event` ("subscriptionChange")
- `listener` ((change: SubscriptionChangeEvent) => void) | +| `sync` | `removeEventListener()` | Removes an event listener for the `subscriptionChange` event. | - `event` ("subscriptionChange")
- `listener` ((change: SubscriptionChangeEvent) => void) | + +### Debug Namespace + +Example: +```js +OneSignal.Debug.setLogLevel(β€œtrace”); +``` + +| Function Name | Description | Argument List | +| --------------- | ---------------------------------------------- | ------------------------------------ | +| `setLogLevel` | Turns on logging with the given log level. | `setLogLevel: string`
- `"trace"`
- `"debug"`
- `"info"`
- `"warn"`
- `"error"` | + +# Limitations + +## January 2023 +### Version 16 (alpha) +It is recommended this version is used **only** in development and staging envrionments. +* Switching between users via `login()` and `logout()` is unsafe. **Please stick to single user testing.** +* Any User namespace calls must be invoked **after** initialization (async). Example: `OneSignal.User.addTag("tag", "2");` +* Aliases will be available in a future release, +* HTTP environments are not supported. +* AMP environments are not supported. +* Identity verification is not functional. +* Outcomes are not functional. + + +# Glossary + +**OneSignal user** + +      *(noun) lowercase* + +      A user of the OneSignal service. + +**user** + +      *(noun) lowercase* + +      An end-user of an application using the OneSignal service. They may or may not have a subscription. + +**user ID** + +      *(noun) lowercase* + +      A OneSignal-provisioned unique identifier for Users (User.onesignal_id). + + +**user external ID** + +      *(noun) lowercase* + +      A customer-provisioned unique identifier for Users (User.external_id). + + +**user alias** + +      *(noun) lowercase* + +      A customer provisioned key-value pair used to uniquely identify a User. + + +**subscription** + +      *(noun) lowercase* + +      An established communication channel between an App and its User, such as a push-subscribed device, email address, or SMS-subscribed phone number. + + +**subscription ID** + +      *(noun) lowercase* + +      A OneSignal-provisioned unique identifier for a single subscription. + + +**notification** + +      *(noun) lowercase* + +      A unidirectional outbound communication message from an App to one or more Users via their Subscriptions. + + +**notification ID** + +      *(noun) lowercase* + +      A OneSignal-provisioned unique identifier for Notifications (Notification.id). + + +**notification external ID** + +      *(noun) lowercase* + +      A customer-provisioned unique identifier for Notifications (Notification.external_id). diff --git a/README.md b/README.md index 4beba90..cb6850d 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ You can find more information on OneSignal [here](https://onesignal.com/). * 🏠 [Homepage](https://onesignal.com) * πŸ–€ [npm](https://www.npmjs.com/package/onesignal-vue) +> 🚧 Version 2 now in Beta! +See our [migration guide](./MigrationGuide.md) to get started. + ## Contents - [Install](#install) - [Usage](#usage) diff --git a/index.ts b/index.ts index c030ed5..5601867 100644 --- a/index.ts +++ b/index.ts @@ -1,80 +1,137 @@ import Vue from 'vue'; const ONESIGNAL_SDK_ID = 'onesignal-sdk'; -const ONE_SIGNAL_SCRIPT_SRC = 'https://cdn.onesignal.com/sdks/OneSignalSDK.js'; -const ONESIGNAL_NOT_SETUP_ERROR = 'OneSignal is not setup correctly.'; -const MAX_TIMEOUT = 30; +const ONE_SIGNAL_SCRIPT_SRC = "https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js"; -const VueApp: any = Vue; +// true if the script is successfully loaded from CDN. let isOneSignalInitialized = false; -const vueOneSignalFunctionQueue: IOneSignalFunctionCall[] = []; +// true if the script fails to load from CDN. A separate flag is necessary +// to disambiguate between a CDN load failure and a delayed call to +// OneSignal#init. +let isOneSignalScriptFailed = false; + +const VueApp: any = Vue; + +window.OneSignalDeferred = window.OneSignalDeferred || []; + +addSDKScript(); /* H E L P E R S */ -const injectScript = () => { +function handleOnError() { + isOneSignalScriptFailed = true; +} + +function addSDKScript() { const script = document.createElement('script'); script.id = ONESIGNAL_SDK_ID; + script.defer = true; script.src = ONE_SIGNAL_SCRIPT_SRC; - script.async = true; - document.head.appendChild(script); -} -const doesOneSignalExist = () => { - if (window.OneSignal) { - return true; + // Always resolve whether or not the script is successfully initialized. + // This is important for users who may block cdn.onesignal.com w/ adblock. + script.onerror = () => { + handleOnError(); } - return false; -} -const processQueuedOneSignalFunctions = () => { - vueOneSignalFunctionQueue.forEach(element => { - const { name, args, promiseResolver } = element; - - if (!!promiseResolver) { - OneSignalVue[name](...args).then((result: any) => { - promiseResolver(result); - }); - } else { - window.OneSignal[name](...args); - } - }); -} - -const setupOneSignalIfMissing = () => { - if (!doesOneSignalExist()) { - window.OneSignal = window.OneSignal || []; - } + document.head.appendChild(script); } /* T Y P E D E C L A R A T I O N S */ declare module 'vue/types/vue' { interface Vue { - $OneSignal: IOneSignal; + $OneSignal: IOneSignalOneSignal; } } declare global { interface Window { - OneSignal: any; + OneSignalDeferred?: OneSignalDeferredLoadedCallback[]; + OneSignal?: IOneSignalOneSignal; + safari?: { + pushNotification: any; + }; + } +} + +/* O N E S I G N A L A P I */ + +/** + * @PublicApi + */ + const init = (options: IInitObject): Promise => { + if (isOneSignalInitialized) { + return Promise.reject(`OneSignal is already initialized.`); + } + + if (!options || !options.appId) { + throw new Error('You need to provide your OneSignal appId.'); + } + + if (!document) { + return Promise.reject(`Document is not defined.`); } + + return new Promise((resolve) => { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.init(options).then(() => { + isOneSignalInitialized = true; + resolve(); + }); + }); + }); +}; + +/** + * The following code is copied directly from the native SDK source file BrowserSupportsPush.ts + * S T A R T + */ + +// Checks if the browser supports push notifications by checking if specific +// classes and properties on them exist +function isPushNotificationsSupported() { + return supportsVapidPush() || supportsSafariPush(); +} + +function isMacOSSafariInIframe(): boolean { + // Fallback detection for Safari on macOS in an iframe context + return window.top !== window && // isContextIframe + navigator.vendor === "Apple Computer, Inc." && // isSafari + navigator.platform === "MacIntel"; // isMacOS +} + +function supportsSafariPush(): boolean { + return (window.safari && typeof window.safari.pushNotification !== "undefined") || + isMacOSSafariInIframe(); } -interface IOneSignalFunctionCall { - name: string; - args: IArguments; - promiseResolver?: Function; +// Does the browser support the standard Push API +function supportsVapidPush(): boolean { + return typeof PushSubscriptionOptions !== "undefined" && + PushSubscriptionOptions.prototype.hasOwnProperty("applicationServerKey"); +} +/* E N D */ + +/** + * @PublicApi + */ +const isPushSupported = (): boolean => { + return isPushNotificationsSupported(); } type Action = (item: T) => void; interface AutoPromptOptions { force?: boolean; forceSlidedownOverNative?: boolean; slidedownPromptOptions?: IOneSignalAutoPromptOptions; } -interface RegisterOptions { modalPrompt?: boolean; httpPermissionRequest?: boolean; slidedown?: boolean; autoAccept?: boolean } -interface SetSMSOptions { identifierAuthHash?: string; } -interface SetEmailOptions { identifierAuthHash?: string; emailAuthHash?: string; } -interface TagsObject { [key: string]: T; } interface IOneSignalAutoPromptOptions { force?: boolean; forceSlidedownOverNative?: boolean; isInUpdateMode?: boolean; categoryOptions?: IOneSignalCategories; } interface IOneSignalCategories { positiveUpdateButton: string; negativeUpdateButton: string; savingButtonText: string; errorButtonText: string; updateMessage: string; tags: IOneSignalTagCategory[]; } interface IOneSignalTagCategory { tag: string; label: string; checked?: boolean; } +type PushSubscriptionNamespaceProperties = { id: string | null | undefined; token: string | null | undefined; optedIn: boolean; }; +type SubscriptionChangeEvent = { previous: PushSubscriptionNamespaceProperties; current: PushSubscriptionNamespaceProperties; }; +type NotificationEventName = 'click' | 'willDisplay' | 'dismiss' | 'permissionChange' | 'permissionPromptDisplay'; +interface NotificationButtonData { action?: string; title?: string; icon?: string; url?: string; } +interface StructuredNotification { id: string; content: string; heading?: string; url?: string; data?: object; rr?: string; icon?: string; image?: string; tag?: string; badge?: string; vibrate?: string; buttons?: NotificationButtonData[]; } +type SlidedownEventName = 'slidedownShown'; +type OneSignalDeferredLoadedCallback = (onesignal: IOneSignalOneSignal) => void; interface IInitObject { appId: string; @@ -97,787 +154,534 @@ interface IInitObject { [key: string]: any; } -interface IOneSignal { - init(options: IInitObject): Promise - on(event: string, listener: (eventData?: any) => void): void - off(event: string, listener: (eventData?: any) => void): void - once(event: string, listener: (eventData?: any) => void): void - isPushNotificationsEnabled(callback?: Action): Promise - showHttpPrompt(options?: AutoPromptOptions): Promise - registerForPushNotifications(options?: RegisterOptions): Promise - setDefaultNotificationUrl(url: string): Promise - setDefaultTitle(title: string): Promise - getTags(callback?: Action): Promise - sendTag(key: string, value: any, callback?: Action): Promise - sendTags(tags: TagsObject, callback?: Action): Promise - deleteTag(tag: string): Promise> - deleteTags(tags: Array, callback?: Action>): Promise> - addListenerForNotificationOpened(callback?: Action): Promise - setSubscription(newSubscription: boolean): Promise - showHttpPermissionRequest(options?: AutoPromptOptions): Promise - showNativePrompt(): Promise - showSlidedownPrompt(options?: AutoPromptOptions): Promise - showCategorySlidedown(options?: AutoPromptOptions): Promise - showSmsSlidedown(options?: AutoPromptOptions): Promise - showEmailSlidedown(options?: AutoPromptOptions): Promise - showSmsAndEmailSlidedown(options?: AutoPromptOptions): Promise - getNotificationPermission(onComplete?: Action): Promise - getUserId(callback?: Action): Promise - getSubscription(callback?: Action): Promise - setEmail(email: string, options?: SetEmailOptions): Promise - setSMSNumber(smsNumber: string, options?: SetSMSOptions): Promise - logoutEmail(): Promise - logoutSMS(): Promise - setExternalUserId(externalUserId: string | undefined | null, authHash?: string): Promise - removeExternalUserId(): Promise - getExternalUserId(): Promise - provideUserConsent(consent: boolean): Promise - getEmailId(callback?: Action): Promise - getSMSId(callback?: Action): Promise - sendOutcome(outcomeName: string, outcomeWeight?: number | undefined): Promise - [index: string]: Function; +interface IOneSignalOneSignal { + Slidedown: IOneSignalSlidedown; + Notifications: IOneSignalNotifications; + Session: IOneSignalSession; + User: IOneSignalUser; + Debug: IOneSignalDebug; + login(externalId: string, jwtToken?: string): Promise; + logout(): Promise; + init(options: IInitObject): Promise; + setConsentGiven(consent: boolean): Promise; + setConsentRequired(requiresConsent: boolean): Promise; +} +interface IOneSignalNotifications { + setDefaultUrl(url: string): Promise; + setDefaultTitle(title: string): Promise; + isPushSupported(): boolean; + getPermissionStatus(onComplete: Action): Promise; + requestPermission(): Promise; + addEventListener(event: NotificationEventName, listener: (obj: any) => void): void; + removeEventListener(event: NotificationEventName, listener: (obj: any) => void): void; +} +interface IOneSignalSlidedown { + promptPush(options?: AutoPromptOptions): Promise; + promptPushCategories(options?: AutoPromptOptions): Promise; + promptSms(options?: AutoPromptOptions): Promise; + promptEmail(options?: AutoPromptOptions): Promise; + promptSmsAndEmail(options?: AutoPromptOptions): Promise; + addEventListener(event: SlidedownEventName, listener: (wasShown: boolean) => void): void; + removeEventListener(event: SlidedownEventName, listener: (wasShown: boolean) => void): void; +} +interface IOneSignalDebug { + setLogLevel(logLevel: string): void; +} +interface IOneSignalSession { + sendOutcome(outcomeName: string, outcomeWeight?: number): Promise; + sendUniqueOutcome(outcomeName: string): Promise; +} +interface IOneSignalUser { + PushSubscription: IOneSignalPushSubscription; + addAlias(label: string, id: string): void; + addAliases(aliases: { [key: string]: string }): void; + removeAlias(label: string): void; + removeAliases(labels: string[]): void; + addEmail(email: string): void; + removeEmail(email: string): void; + addSms(smsNumber: string): void; + removeSms(smsNumber: string): void; +} +interface IOneSignalPushSubscription { + id: string | null | undefined; + token: string | null | undefined; + optedIn: boolean | undefined; + optIn(): Promise; + optOut(): Promise; + addEventListener(event: 'subscriptionChange', listener: (change: SubscriptionChangeEvent) => void): void; + removeEventListener(event: 'subscriptionChange', listener: (change: SubscriptionChangeEvent) => void): void; } - -/* O N E S I G N A L A P I */ - -function init(options: IInitObject) { - return new Promise(resolve => { - if (isOneSignalInitialized) { - return; +function oneSignalLogin(externalId: string, jwtToken?: string): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); } - injectScript(); - setupOneSignalIfMissing(); - window.OneSignal.push(() => { - window.OneSignal.init(options); - }) - - const timeout = setTimeout(() => { - console.error(ONESIGNAL_NOT_SETUP_ERROR); - }, MAX_TIMEOUT * 1_000); - - window.OneSignal.push(() => { - clearTimeout(timeout); - isOneSignalInitialized = true; - processQueuedOneSignalFunctions(); - resolve(); - }); + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.login(externalId, jwtToken) + .then(value => resolve(value)) + .catch(error => reject(error)); + }); + } catch (error) { + reject(error); + } }); } - function on(event: string, listener: (eventData?: any) => void): void { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'on', - args: arguments, - }); - return; +function oneSignalLogout(): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); } - window.OneSignal.push(() => { - window.OneSignal.on(event, listener) - }); - } - - function off(event: string, listener: (eventData?: any) => void): void { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'off', - args: arguments, + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.logout() + .then(value => resolve(value)) + .catch(error => reject(error)); }); - return; + } catch (error) { + reject(error); } + }); +} - window.OneSignal.push(() => { - window.OneSignal.off(event, listener) - }); - } - - function once(event: string, listener: (eventData?: any) => void): void { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'once', - args: arguments, - }); - return; +function oneSignalSetConsentGiven(consent: boolean): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); } - window.OneSignal.push(() => { - window.OneSignal.once(event, listener) - }); - } - - function isPushNotificationsEnabled(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'isPushNotificationsEnabled', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.isPushNotificationsEnabled(callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.setConsentGiven(consent) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function showHttpPrompt(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showHttpPrompt', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showHttpPrompt(options) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function oneSignalSetConsentRequired(requiresConsent: boolean): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function registerForPushNotifications(options?: RegisterOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'registerForPushNotifications', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.registerForPushNotifications(options) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.setConsentRequired(requiresConsent) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function setDefaultNotificationUrl(url: string): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setDefaultNotificationUrl', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setDefaultNotificationUrl(url) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownPromptPush(options?: AutoPromptOptions): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function setDefaultTitle(title: string): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setDefaultTitle', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setDefaultTitle(title) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.promptPush(options) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function getTags(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getTags', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getTags(callback) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownPromptPushCategories(options?: AutoPromptOptions): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function sendTag(key: string, value: any, callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'sendTag', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.sendTag(key, value, callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.promptPushCategories(options) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function sendTags(tags: TagsObject, callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'sendTags', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.sendTags(tags, callback) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownPromptSms(options?: AutoPromptOptions): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function deleteTag(tag: string): Promise> { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'deleteTag', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.deleteTag(tag) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.promptSms(options) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function deleteTags(tags: Array, callback?: Action>): Promise> { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'deleteTags', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.deleteTags(tags, callback) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownPromptEmail(options?: AutoPromptOptions): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function addListenerForNotificationOpened(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'addListenerForNotificationOpened', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.addListenerForNotificationOpened(callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.promptEmail(options) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function setSubscription(newSubscription: boolean): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setSubscription', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setSubscription(newSubscription) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownPromptSmsAndEmail(options?: AutoPromptOptions): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function showHttpPermissionRequest(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showHttpPermissionRequest', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showHttpPermissionRequest(options) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.promptSmsAndEmail(options) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function showNativePrompt(): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showNativePrompt', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showNativePrompt() - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownAddEventListener(event: SlidedownEventName, listener: (wasShown: boolean) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.addEventListener(event, listener) + }); +} - function showSlidedownPrompt(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showSlidedownPrompt', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showSlidedownPrompt(options) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function slidedownRemoveEventListener(event: SlidedownEventName, listener: (wasShown: boolean) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Slidedown.removeEventListener(event, listener) + }); +} - function showCategorySlidedown(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showCategorySlidedown', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showCategorySlidedown(options) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsSetDefaultUrl(url: string): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function showSmsSlidedown(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showSmsSlidedown', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showSmsSlidedown(options) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.setDefaultUrl(url) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function showEmailSlidedown(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showEmailSlidedown', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showEmailSlidedown(options) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsSetDefaultTitle(title: string): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function showSmsAndEmailSlidedown(options?: AutoPromptOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'showSmsAndEmailSlidedown', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.showSmsAndEmailSlidedown(options) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.setDefaultTitle(title) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function getNotificationPermission(onComplete?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getNotificationPermission', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getNotificationPermission(onComplete) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsGetPermissionStatus(onComplete: Action): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function getUserId(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getUserId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getUserId(callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.getPermissionStatus(onComplete) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function getSubscription(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getSubscription', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getSubscription(callback) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsRequestPermission(): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function setEmail(email: string, options?: SetEmailOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setEmail', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setEmail(email, options) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.requestPermission() .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function setSMSNumber(smsNumber: string, options?: SetSMSOptions): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setSMSNumber', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setSMSNumber(smsNumber, options) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsAddEventListener(event: 'click' | 'willDisplay' | 'dismiss', listener: (obj: StructuredNotification) => void): void; +function notificationsAddEventListener(event: 'permissionChange', listener: (obj: { to: NotificationPermission }) => void): void; +function notificationsAddEventListener(event: 'permissionPromptDisplay', listener: () => void): void; - function logoutEmail(): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'logoutEmail', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.logoutEmail() - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsAddEventListener(event: NotificationEventName, listener: (obj: any) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.addEventListener(event, listener) + }); +} - function logoutSMS(): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'logoutSMS', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.logoutSMS() - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsRemoveEventListener(event: 'click' | 'willDisplay' | 'dismiss', listener: (obj: StructuredNotification) => void): void; +function notificationsRemoveEventListener(event: 'permissionChange', listener: (obj: { to: NotificationPermission }) => void): void; +function notificationsRemoveEventListener(event: 'permissionPromptDisplay', listener: () => void): void; - function setExternalUserId(externalUserId: string | undefined | null, authHash?: string): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'setExternalUserId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.setExternalUserId(externalUserId, authHash) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function notificationsRemoveEventListener(event: NotificationEventName, listener: (obj: any) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Notifications.removeEventListener(event, listener) + }); +} - function removeExternalUserId(): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'removeExternalUserId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.removeExternalUserId() - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function sessionSendOutcome(outcomeName: string, outcomeWeight?: number): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function getExternalUserId(): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getExternalUserId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getExternalUserId() + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Session.sendOutcome(outcomeName, outcomeWeight) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} - function provideUserConsent(consent: boolean): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'provideUserConsent', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.provideUserConsent(consent) - .then(value => resolve(value)) - .catch(error => reject(error)); - }); - }); - } +function sessionSendUniqueOutcome(outcomeName: string): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function getEmailId(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getEmailId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getEmailId(callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Session.sendUniqueOutcome(outcomeName) .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} + +function userAddAlias(label: string, id: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.addAlias(label, id) + }); +} + +function userAddAliases(aliases: { [key: string]: string }): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.addAliases(aliases) + }); +} + +function userRemoveAlias(label: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.removeAlias(label) + }); +} + +function userRemoveAliases(labels: string[]): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.removeAliases(labels) + }); +} + +function userAddEmail(email: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.addEmail(email) + }); +} + +function userRemoveEmail(email: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.removeEmail(email) + }); +} + +function userAddSms(smsNumber: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.addSms(smsNumber) + }); +} + +function userRemoveSms(smsNumber: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.removeSms(smsNumber) + }); +} + +function pushSubscriptionOptIn(): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function getSMSId(callback?: Action): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'getSMSId', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.getSMSId(callback) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.PushSubscription.optIn() .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} + +function pushSubscriptionOptOut(): Promise { + return new Promise(function (resolve, reject) { + if (isOneSignalScriptFailed) { + reject(); + } - function sendOutcome(outcomeName: string, outcomeWeight?: number | undefined): Promise { - return new Promise(function (resolve, reject) { - if (!doesOneSignalExist()) { - vueOneSignalFunctionQueue.push({ - name: 'sendOutcome', - args: arguments, - promiseResolver: resolve, - }); - return; - } - - window.OneSignal.push(() => { - window.OneSignal.sendOutcome(outcomeName, outcomeWeight) + try { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.PushSubscription.optOut() .then(value => resolve(value)) .catch(error => reject(error)); }); - }); - } + } catch (error) { + reject(error); + } + }); +} + +function pushSubscriptionAddEventListener(event: 'subscriptionChange', listener: (change: SubscriptionChangeEvent) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.PushSubscription.addEventListener(event, listener) + }); +} + +function pushSubscriptionRemoveEventListener(event: 'subscriptionChange', listener: (change: SubscriptionChangeEvent) => void): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.User.PushSubscription.removeEventListener(event, listener) + }); +} + +function debugSetLogLevel(logLevel: string): void { + window.OneSignalDeferred?.push((OneSignal) => { + OneSignal.Debug.setLogLevel(logLevel) + }); +} +const PushSubscriptionNamespace: IOneSignalPushSubscription = { + get id(): string | null | undefined { return window.OneSignal?.User?.PushSubscription?.id }, + get token(): string | null | undefined { return window.OneSignal?.User?.PushSubscription?.token }, + get optedIn(): boolean | undefined { return window.OneSignal?.User?.PushSubscription?.optedIn }, + optIn: pushSubscriptionOptIn, + optOut: pushSubscriptionOptOut, + addEventListener: pushSubscriptionAddEventListener, + removeEventListener: pushSubscriptionRemoveEventListener, +}; + +const UserNamespace: IOneSignalUser = { + addAlias: userAddAlias, + addAliases: userAddAliases, + removeAlias: userRemoveAlias, + removeAliases: userRemoveAliases, + addEmail: userAddEmail, + removeEmail: userRemoveEmail, + addSms: userAddSms, + removeSms: userRemoveSms, + PushSubscription: PushSubscriptionNamespace, +}; + +const SessionNamespace: IOneSignalSession = { + sendOutcome: sessionSendOutcome, + sendUniqueOutcome: sessionSendUniqueOutcome, +}; + +const DebugNamespace: IOneSignalDebug = { + setLogLevel: debugSetLogLevel, +}; + +const SlidedownNamespace: IOneSignalSlidedown = { + promptPush: slidedownPromptPush, + promptPushCategories: slidedownPromptPushCategories, + promptSms: slidedownPromptSms, + promptEmail: slidedownPromptEmail, + promptSmsAndEmail: slidedownPromptSmsAndEmail, + addEventListener: slidedownAddEventListener, + removeEventListener: slidedownRemoveEventListener, +}; + +const NotificationsNamespace: IOneSignalNotifications = { + setDefaultUrl: notificationsSetDefaultUrl, + setDefaultTitle: notificationsSetDefaultTitle, + isPushSupported, + getPermissionStatus: notificationsGetPermissionStatus, + requestPermission: notificationsRequestPermission, + addEventListener: notificationsAddEventListener, + removeEventListener: notificationsRemoveEventListener, +}; -const OneSignalVue: IOneSignal = { +const OneSignalNamespace: IOneSignalOneSignal = { + login: oneSignalLogin, + logout: oneSignalLogout, init, - on, - off, - once, - isPushNotificationsEnabled, - showHttpPrompt, - registerForPushNotifications, - setDefaultNotificationUrl, - setDefaultTitle, - getTags, - sendTag, - sendTags, - deleteTag, - deleteTags, - addListenerForNotificationOpened, - setSubscription, - showHttpPermissionRequest, - showNativePrompt, - showSlidedownPrompt, - showCategorySlidedown, - showSmsSlidedown, - showEmailSlidedown, - showSmsAndEmailSlidedown, - getNotificationPermission, - getUserId, - getSubscription, - setEmail, - setSMSNumber, - logoutEmail, - logoutSMS, - setExternalUserId, - removeExternalUserId, - getExternalUserId, - provideUserConsent, - getEmailId, - getSMSId, - sendOutcome, + setConsentGiven: oneSignalSetConsentGiven, + setConsentRequired: oneSignalSetConsentRequired, + Slidedown: SlidedownNamespace, + Notifications: NotificationsNamespace, + Session: SessionNamespace, + User: UserNamespace, + Debug: DebugNamespace, }; const OneSignalVuePlugin = { install(app: typeof VueApp) { - app.prototype.$OneSignal = OneSignalVue as IOneSignal; + app.prototype.$OneSignal = OneSignalNamespace as IOneSignalOneSignal; } } diff --git a/package.json b/package.json index db9d682..e398a69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "onesignal-vue", - "version": "1.0.3", + "version": "2.0.0-beta.2", "description": "Vue OneSignal Plugin: Make it easy to integrate OneSignal with your Vue App!", "author": "rgomezp", "contributors": [